--- gcc/cp/decl2.c 2018/04/24 18:20:21 1.1.1.1 +++ gcc/cp/decl2.c 2018/04/24 18:33:17 1.1.1.3 @@ -1,5 +1,5 @@ /* Process declarations and variables for C compiler. - Copyright (C) 1988, 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -16,7 +16,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Process declarations and symbol lookup for C front end. @@ -34,8 +35,9 @@ the Free Software Foundation, 675 Mass A #include "cp-tree.h" #include "decl.h" #include "lex.h" +#include "output.h" +#include "defaults.h" -extern tree grokdeclarator (); extern tree get_file_function_name (); extern tree cleanups_this_call; static void grok_function_init (); @@ -55,7 +57,7 @@ static tree saved_inlines; /* Used to help generate temporary names which are unique within a function. Reset to 0 by start_function. */ -static int temp_name_counter; +int temp_name_counter; /* Same, but not reset. Local temp variables and global temp variables can have the same name. */ @@ -64,6 +66,10 @@ static int global_temp_name_counter; /* Flag used when debugging spew.c */ extern int spew_debug; + +/* Functions called along with real static constructors and destructors. */ + +tree static_ctors, static_dtors; /* C (and C++) language-specific option variables. */ @@ -80,6 +86,10 @@ int flag_short_double; int flag_no_asm; +/* Nonzero means don't recognize any extension keywords. */ + +int flag_no_gnu_keywords; + /* Nonzero means don't recognize the non-ANSI builtin functions. */ int flag_no_builtin; @@ -99,11 +109,12 @@ int flag_signed_bitfields = 1; /* Nonzero means handle `#ident' directives. 0 means ignore them. */ -int flag_no_ident = 0; +int flag_no_ident; -/* Nonzero means disable GNU extensions. */ +/* Nonzero means enable obscure ANSI features and disable GNU extensions + that might cause ANSI-compliant code to be miscompiled. */ -int flag_ansi = 0; +int flag_ansi; /* Nonzero means do emit exported implementations of functions even if they can be inlined. */ @@ -113,13 +124,13 @@ int flag_implement_inlines = 1; /* Nonzero means do emit exported implementations of templates, instead of multiple static copies in each file that needs a definition. */ -int flag_external_templates = 0; +int flag_external_templates; /* Nonzero means that the decision to emit or not emit the implementation of a template depends on where the template is instantiated, rather than where it is defined. */ -int flag_alt_external_templates = 0; +int flag_alt_external_templates; /* Nonzero means that implicit instantiations will be emitted if needed. */ @@ -135,11 +146,13 @@ int warn_implicit = 1; int warn_ctor_dtor_privacy = 1; /* True if we want to implement vtbvales using "thunks". - The default is off now, but will be on later. + The default is off now, but will be on later. */ + +int flag_vtable_thunks; + +/* True if we want to deal with repository information. */ - Also causes output of vtables to be controlled by whether - we seen the class's first non-inline virtual function. */ -int flag_vtable_thunks = 0; +int flag_use_repository; /* Nonzero means give string constants the type `const char *' to get extra warnings from them. These warnings will be too numerous @@ -198,7 +211,7 @@ int warn_conversion; /* Warn if adding () is suggested. */ -int warn_parentheses = 1; +int warn_parentheses; /* Non-zero means warn in function declared in derived class has the same name as a virtual in the base class, but fails to match the @@ -215,7 +228,7 @@ int warn_extern_inline; /* Non-zero means warn when the compiler will reorder code. */ int warn_reorder; -/* Non-zero means warn when sysnthesis behavior differs from Cfront's. */ +/* Non-zero means warn when synthesis behavior differs from Cfront's. */ int warn_synth; /* Nonzero means `$' can be in an identifier. @@ -229,6 +242,7 @@ int dollars_in_ident = DOLLARS_IN_IDENTI /* Nonzero for -fno-strict-prototype switch: do not consider empty argument prototype to mean function takes no arguments. */ +int flag_strict_prototype = 2; int strict_prototype = 1; int strict_prototypes_lang_c, strict_prototypes_lang_cplusplus = 1; @@ -301,9 +315,9 @@ int flag_cadillac; that can be collected when they become garbage. */ int flag_gc; -/* Controls whether compiler generates 'dossiers' that give +/* Controls whether compiler generates 'type descriptor' that give run-time type information. */ -int flag_dossier; +int flag_rtti; /* Nonzero if we wish to output cross-referencing information for the GNU class browser. */ @@ -319,21 +333,42 @@ extern int flag_gnu_xref; In general, it is `reasonable' to assume that for many programs, and better code can be generated in that case. */ -int flag_assume_nonnull_objects; +int flag_assume_nonnull_objects = 1; /* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes) objects. */ + int flag_huge_objects; /* Nonzero if we want to conserve space in the .o files. We do this by putting uninitialized data and runtime initialized data into - .common instead of .data at the expense of not flaging multiple + .common instead of .data at the expense of not flagging multiple definitions. */ + int flag_conserve_space; /* Nonzero if we want to obey access control semantics. */ + int flag_access_control = 1; +/* Nonzero if we want to understand the operator names, i.e. 'bitand'. */ + +int flag_operator_names; + +/* Nonzero if we want to check the return value of new and avoid calling + constructors if it is a null pointer. */ + +int flag_check_new; + +/* Nonzero if we want the new ANSI rules for pushing a new scope for `for' + initialization variables. + 0: Old rules, set by -fno-for-scope. + 2: New ANSI rules, set by -ffor-scope. + 1: Try to implement new ANSI rules, but with backup compatibility + (and warnings). This is the default, for now. */ + +int flag_new_for_scope = 1; + /* Table of language-dependent -f options. STRING is the option name. VARIABLE is the address of the variable. ON_VALUE is the value to store in VARIABLE @@ -355,7 +390,7 @@ static struct { char *string; int *varia {"labels-ok", &flag_labels_ok, 1}, {"stats", &flag_detailed_statistics, 1}, {"this-is-variable", &flag_this_is_variable, 1}, - {"strict-prototype", &strict_prototypes_lang_cplusplus, 1}, + {"strict-prototype", &flag_strict_prototype, 1}, {"all-virtual", &flag_all_virtual, 1}, {"memoize-lookups", &flag_memoize_lookups, 1}, {"elide-constructors", &flag_elide_constructors, 1}, @@ -365,7 +400,7 @@ static struct { char *string; int *varia {"dollars-in-identifiers", &dollars_in_ident, 1}, {"enum-int-equiv", &flag_int_enum_equivalence, 1}, {"gc", &flag_gc, 1}, - {"dossier", &flag_dossier, 1}, + {"rtti", &flag_rtti, 1}, {"xref", &flag_gnu_xref, 1}, {"nonnull-objects", &flag_assume_nonnull_objects, 1}, {"implement-inlines", &flag_implement_inlines, 1}, @@ -376,7 +411,12 @@ static struct { char *string; int *varia {"vtable-thunks", &flag_vtable_thunks, 1}, {"short-temps", &flag_short_temps, 1}, {"access-control", &flag_access_control, 1}, - {"nonansi-builtins", &flag_no_nonansi_builtin, 0} + {"nonansi-builtins", &flag_no_nonansi_builtin, 0}, + {"gnu-keywords", &flag_no_gnu_keywords, 0}, + {"operator-names", &flag_operator_names, 1}, + {"check-new", &flag_check_new, 1}, + {"repo", &flag_use_repository, 1}, + {"for-scope", &flag_new_for_scope, 2} }; /* Decode the string P as a language-specific option. @@ -389,7 +429,7 @@ lang_decode_option (p) { if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional")) flag_traditional = 1, dollars_in_ident = 1, flag_writable_strings = 1, - flag_this_is_variable = 1; + flag_this_is_variable = 1, flag_new_for_scope = 0; /* The +e options are for cfront compatibility. They come in as `-+eN', to kludge around gcc.c's argument handling. */ else if (p[0] == '-' && p[1] == '+' && p[2] == 'e') @@ -442,14 +482,14 @@ lang_decode_option (p) { flag_gc = 1; /* This must come along for the ride. */ - flag_dossier = 1; + flag_rtti = 1; found = 1; } else if (! strcmp (p, "no-gc")) { flag_gc = 0; /* This must come along for the ride. */ - flag_dossier = 0; + flag_rtti = 0; found = 1; } else if (! strcmp (p, "alt-external-templates")) @@ -466,6 +506,13 @@ lang_decode_option (p) else if (!strcmp (p, "ansi-overloading")) { warning ("-fansi-overloading is no longer meaningful"); + found = 1; + } + else if (!strcmp (p, "repo")) + { + flag_use_repository = 1; + flag_implicit_templates = 0; + found = 1; } else for (j = 0; !found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]); @@ -552,6 +599,7 @@ lang_decode_option (p) warn_ctor_dtor_privacy = setting; warn_switch = setting; warn_format = setting; + warn_parentheses = setting; warn_missing_braces = setting; warn_extern_inline = setting; warn_nonvdtor = setting; @@ -569,8 +617,8 @@ lang_decode_option (p) else return 0; } else if (!strcmp (p, "-ansi")) - flag_no_asm = 1, dollars_in_ident = 0, flag_no_nonansi_builtin = 1, - flag_ansi = 1; + dollars_in_ident = 0, flag_no_nonansi_builtin = 1, flag_ansi = 1, + flag_no_gnu_keywords = 1, flag_operator_names = 1; #ifdef SPEW_DEBUG /* Undocumented, only ever used when you're invoking cc1plus by hand, since it's probably safe to assume no sane person would ever want to use this @@ -628,7 +676,7 @@ grok_method_quals (ctype, function, qual ? TREE_CHAIN (TYPE_ARG_TYPES (fntype)) : TYPE_ARG_TYPES (fntype))); if (raises) - fntype = build_exception_variant (ctype, fntype, raises); + fntype = build_exception_variant (fntype, raises); TREE_TYPE (function) = fntype; return ctype; @@ -657,11 +705,32 @@ substitute_nice_name (decl) interface/implementation is not used all the times it should be, inform the user. */ void -warn_if_unknown_interface () +warn_if_unknown_interface (decl) + tree decl; { static int already_warned = 0; - if (++already_warned == 1) - warning ("templates that are built with -fexternal-templates should be in files that have #pragma interface/implementation"); + if (already_warned++) + return; + + if (flag_alt_external_templates) + { + struct tinst_level *til = tinst_for_decl (); + int sl = lineno; + char *sf = input_filename; + + if (til) + { + lineno = til->line; + input_filename = til->file; + } + cp_warning ("template `%#D' instantiated in file without #pragma interface", + decl); + lineno = sl; + input_filename = sf; + } + else + cp_warning_at ("template `%#D' defined in file without #pragma interface", + decl); } /* A subroutine of the parser, to handle a component list. */ @@ -707,15 +776,10 @@ grok_x_components (specs, components) tcode = class_type_node; else if (IS_SIGNATURE(t)) tcode = signature_type_node; - else if (CLASSTYPE_DECLARED_EXCEPTION(t)) - tcode = exception_type_node; - t = xref_defn_tag(tcode, TYPE_IDENTIFIER(t), NULL_TREE); + t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0); if (TYPE_CONTEXT(t)) CLASSTYPE_NO_GLOBALIZE(t) = 1; - if (TYPE_LANG_SPECIFIC (t) - && CLASSTYPE_DECLARED_EXCEPTION (t)) - shadow_tag (specs); return NULL_TREE; break; @@ -726,7 +790,7 @@ grok_x_components (specs, components) else tcode = enum_type_node; - t = xref_defn_tag(tcode, TYPE_IDENTIFIER(t), NULL_TREE); + t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0); if (TREE_CODE(t) == UNION_TYPE && TYPE_CONTEXT(t)) CLASSTYPE_NO_GLOBALIZE(t) = 1; if (TREE_CODE (t) == UNION_TYPE @@ -802,6 +866,8 @@ grokclassfn (ctype, cname, function, fla tree arg_types; tree parm; tree qualtype; + tree fntype = TREE_TYPE (function); + tree raises = TYPE_RAISES_EXCEPTIONS (fntype); if (fn_name == NULL_TREE) { @@ -822,10 +888,11 @@ grokclassfn (ctype, cname, function, fla /* Right now we just make this a pointer. But later we may wish to make it special. */ tree type = TREE_VALUE (arg_types); + int constp = 1; if ((flag_this_is_variable > 0) && (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))) - type = TYPE_MAIN_VARIANT (type); + constp = 0; if (DECL_CONSTRUCTOR_P (function)) { @@ -852,7 +919,7 @@ grokclassfn (ctype, cname, function, fla /* We can make this a register, so long as we don't accidentally complain if someone tries to take its address. */ DECL_REGISTER (parm) = 1; - if (TYPE_READONLY (type)) + if (constp) TREE_READONLY (parm) = 1; TREE_CHAIN (parm) = last_function_parms; last_function_parms = parm; @@ -896,8 +963,13 @@ grokclassfn (ctype, cname, function, fla /* This is the same chain as DECL_ARGUMENTS (...). */ TREE_CHAIN (last_function_parms) = parm; - TREE_TYPE (function) = build_cplus_method_type (qualtype, void_type_node, - arg_types); + fntype = build_cplus_method_type (qualtype, void_type_node, + arg_types); + if (raises) + { + fntype = build_exception_variant (fntype, raises); + } + TREE_TYPE (function) = fntype; TYPE_HAS_DESTRUCTOR (ctype) = 1; } else @@ -908,10 +980,14 @@ grokclassfn (ctype, cname, function, fla { arg_types = hash_tree_chain (integer_type_node, TREE_CHAIN (arg_types)); - TREE_TYPE (function) - = build_cplus_method_type (qualtype, - TREE_TYPE (TREE_TYPE (function)), - arg_types); + fntype = build_cplus_method_type (qualtype, + TREE_TYPE (TREE_TYPE (function)), + arg_types); + if (raises) + { + fntype = build_exception_variant (fntype, raises); + } + TREE_TYPE (function) = fntype; arg_types = TYPE_ARG_TYPES (TREE_TYPE (function)); } @@ -919,7 +995,7 @@ grokclassfn (ctype, cname, function, fla if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE) /* Only true for static member functions. */ - these_arg_types = hash_tree_chain (TYPE_POINTER_TO (qualtype), + these_arg_types = hash_tree_chain (build_pointer_type (qualtype), arg_types); DECL_ASSEMBLER_NAME (function) @@ -928,7 +1004,7 @@ grokclassfn (ctype, cname, function, fla #if 0 /* This code is going into the compiler, but currently, it makes - libg++/src/Interger.cc not compile. The problem is that the nice name + libg++/src/Integer.cc not compile. The problem is that the nice name winds up going into the symbol table, and conversion operations look for the manged name. */ substitute_nice_name (function); @@ -990,6 +1066,7 @@ grok_array_decl (array_expr, index_exp) tree array_expr, index_exp; { tree type = TREE_TYPE (array_expr); + tree p1, p2, i1, i2; if (type == error_mark_node || index_exp == error_mark_node) return error_mark_node; @@ -1012,28 +1089,38 @@ grok_array_decl (array_expr, index_exp) array_expr, index_exp, NULL_TREE); /* Otherwise, create an ARRAY_REF for a pointer or array type. */ - if (TREE_CODE (type) == POINTER_TYPE - || TREE_CODE (type) == ARRAY_TYPE) - return build_array_ref (array_expr, index_exp); - - /* Woops, looks like they did something like `5[a]' instead of `a[5]'. - We don't emit a warning or error for this, since it's allowed - by ARM $8.2.4. */ - type = TREE_TYPE (index_exp); + if (TREE_CODE (type) == ARRAY_TYPE) + p1 = array_expr; + else + p1 = build_expr_type_conversion (WANT_POINTER, array_expr, 0); - if (TREE_CODE (type) == OFFSET_TYPE - || TREE_CODE (type) == REFERENCE_TYPE) - type = TREE_TYPE (type); + if (TREE_CODE (TREE_TYPE (index_exp)) == ARRAY_TYPE) + p2 = index_exp; + else + p2 = build_expr_type_conversion (WANT_POINTER, index_exp, 0); + + i1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, array_expr, 0); + i2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, index_exp, 0); + + if ((p1 && i2) && (i1 && p2)) + error ("ambiguous conversion for array subscript"); + + if (p1 && i2) + array_expr = p1, index_exp = i2; + else if (i1 && p2) + array_expr = p2, index_exp = i1; + else + { + cp_error ("invalid types `%T[%T]' for array subscript", + type, TREE_TYPE (index_exp)); + return error_mark_node; + } - if (TREE_CODE (type) == POINTER_TYPE - || TREE_CODE (type) == ARRAY_TYPE) - return build_array_ref (index_exp, array_expr); - - /* The expression E1[E2] is identical (by definition) to *((E1)+(E2)). */ - return build_indirect_ref (build_binary_op (PLUS_EXPR, array_expr, - index_exp, 1), - "array indexing"); + if (array_expr == error_mark_node || index_exp == error_mark_node) + error ("ambiguous conversion for array subscript"); + + return build_array_ref (array_expr, index_exp); } /* Given the cast expression EXP, checking out its validity. Either return @@ -1075,19 +1162,22 @@ delete_sanity (exp, size, doing_vec, use return error_mark_node; } - /* Deleting a pointer with the value zero is legal and has no effect. */ + /* Deleting a pointer with the value zero is valid and has no effect. */ if (integer_zerop (t)) return build1 (NOP_EXPR, void_type_node, t); } if (code == POINTER_TYPE) { +#if 0 + /* As of Valley Forge, you can delete a pointer to constant. */ /* You can't delete a pointer to constant. */ if (TREE_READONLY (TREE_TYPE (type))) { error ("`const *' cannot be deleted"); return error_mark_node; } +#endif /* You also can't delete functions. */ if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) { @@ -1114,16 +1204,29 @@ delete_sanity (exp, size, doing_vec, use return build_vec_delete (t, maxindex, elt_size, integer_one_node, integer_two_node, use_global_delete); else - return build_delete (type, t, integer_three_node, - LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, - use_global_delete); + { + if (IS_AGGR_TYPE (TREE_TYPE (type)) + && TYPE_GETS_REG_DELETE (TREE_TYPE (type))) + { + /* Only do access checking here; we'll be calling op delete + from the destructor. */ + tree tmp = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, t, + size_zero_node, NULL_TREE); + if (tmp == error_mark_node) + return error_mark_node; + } + + return build_delete (type, t, integer_three_node, + LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE, + use_global_delete); + } } /* Sanity check: report error if this function FUNCTION is not really a member of the class (CTYPE) it is supposed to belong to. CNAME is the same here as it is for grokclassfn above. */ -void +tree check_classfn (ctype, cname, function) tree ctype, cname, function; { @@ -1139,7 +1242,7 @@ check_classfn (ctype, cname, function) end = TREE_VEC_END (method_vec); /* First suss out ctors and dtors. */ - if (*methods && fn_name == cname) + if (*methods && fn_name == DECL_NAME (*methods)) goto got_it; while (++methods != end) @@ -1151,7 +1254,37 @@ check_classfn (ctype, cname, function) while (fndecl) { if (DECL_ASSEMBLER_NAME (function) == DECL_ASSEMBLER_NAME (fndecl)) - return; + return fndecl; +#if 0 + /* This should work, but causes libg++ to fail + make check-tFix. */ + /* We have to do more extensive argument checking here, as + the name may have been changed by asm("new_name"). */ + if (decls_match (function, fndecl)) + return fndecl; +#else + if (DECL_NAME (function) == DECL_NAME (fndecl)) + { + tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function)); + tree p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); + + /* Get rid of the this parameter on functions that become + static. */ + if (DECL_STATIC_FUNCTION_P (fndecl) + && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) + p1 = TREE_CHAIN (p1); + + if (comptypes (TREE_TYPE (TREE_TYPE (function)), + TREE_TYPE (TREE_TYPE (fndecl)), 1) + && compparms (p1, p2, 3)) + { + if (DECL_STATIC_FUNCTION_P (fndecl) + && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE) + revert_static_member_fn (&function, NULL, NULL); + return fndecl; + } + } +#endif fndecl = DECL_CHAIN (fndecl); } break; /* loser */ @@ -1160,8 +1293,15 @@ check_classfn (ctype, cname, function) } if (methods != end) - cp_error ("argument list for `%#D' does not match any in class `%T'", - function, ctype); + { + tree fndecl = *methods; + cp_error ("prototype for `%#D' does not match any in class `%T'", + function, ctype); + cp_error_at ("candidate%s: %+#D", DECL_CHAIN (fndecl) ? "s are" : " is", + fndecl); + while (fndecl = DECL_CHAIN (fndecl), fndecl) + cp_error_at (" %#D", fndecl); + } else { methods = 0; @@ -1172,6 +1312,7 @@ check_classfn (ctype, cname, function) /* If we did not find the method in the class, add it to avoid spurious errors. */ add_method (ctype, methods, function); + return NULL_TREE; } /* Process the specs, declarator (NULL if omitted) and width (NULL if omitted) @@ -1195,11 +1336,12 @@ check_classfn (ctype, cname, function) CHANGES TO CODE IN `start_method'. */ tree -grokfield (declarator, declspecs, raises, init, asmspec_tree) - tree declarator, declspecs, raises, init, asmspec_tree; +grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist) + tree declarator, declspecs, raises, init, asmspec_tree, attrlist; { register tree value; char *asmspec = 0; + int flags = LOOKUP_ONLYCONVERTING; /* Convert () initializers to = initializers. */ if (init == NULL_TREE && declarator != NULL_TREE @@ -1211,6 +1353,7 @@ grokfield (declarator, declspecs, raises { init = TREE_OPERAND (declarator, 1); declarator = TREE_OPERAND (declarator, 0); + flags = 0; } if (init @@ -1219,7 +1362,8 @@ grokfield (declarator, declspecs, raises && TREE_CHAIN (init) == NULL_TREE) init = NULL_TREE; - value = grokdeclarator (declarator, declspecs, FIELD, init != 0, raises); + value = grokdeclarator (declarator, declspecs, FIELD, init != 0, + raises, NULL_TREE); if (! value) return value; /* friend or constructor went bad. */ @@ -1239,6 +1383,17 @@ grokfield (declarator, declspecs, raises DECL_CONTEXT (value) = current_class_type; DECL_CLASS_CONTEXT (value) = current_class_type; CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1; + + /* If we declare a typedef name for something that has no name, + the typedef name is used for linkage. See 7.1.3 p4 94/0158. */ + if (TYPE_NAME (TREE_TYPE (value)) + && TREE_CODE (TYPE_NAME (TREE_TYPE (value))) == TYPE_DECL + && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (value)))) + { + TYPE_NAME (TREE_TYPE (value)) = value; + TYPE_STUB_DECL (TREE_TYPE (value)) = value; + } + pushdecl_class_level (value); return value; } @@ -1319,14 +1474,18 @@ grokfield (declarator, declspecs, raises } } - /* The corresponding pop_obstacks is in finish_decl. */ + /* The corresponding pop_obstacks is in cp_finish_decl. */ push_obstacks_nochange (); + if (attrlist) + cplus_decl_attributes (value, TREE_PURPOSE (attrlist), + TREE_VALUE (attrlist)); + if (TREE_CODE (value) == VAR_DECL) { /* We cannot call pushdecl here, because that would fill in the value of our TREE_CHAIN. Instead, we - modify finish_decl to do the right thing, namely, to + modify cp_finish_decl to do the right thing, namely, to put this decl out straight away. */ if (TREE_PUBLIC (value)) { @@ -1358,23 +1517,29 @@ grokfield (declarator, declspecs, raises DECL_INITIAL (value) = init; DECL_IN_AGGR_P (value) = 1; - finish_decl (value, init, asmspec_tree, 1); + cp_finish_decl (value, init, asmspec_tree, 1, flags); pushdecl_class_level (value); return value; } if (TREE_CODE (value) == FIELD_DECL) { if (asmspec) - DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec); + { + /* This must override the asm specifier which was placed + by grokclassfn. Lay this out fresh. */ + DECL_RTL (value) = NULL_RTX; + DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec); + } if (DECL_INITIAL (value) == error_mark_node) init = error_mark_node; - finish_decl (value, init, asmspec_tree, 1); + cp_finish_decl (value, init, asmspec_tree, 1, flags); DECL_INITIAL (value) = init; DECL_IN_AGGR_P (value) = 1; return value; } if (TREE_CODE (value) == FUNCTION_DECL) { + check_default_args (value); if (DECL_CHAIN (value) != NULL_TREE) { /* Need a fresh node here so that we don't get circularity @@ -1383,7 +1548,14 @@ grokfield (declarator, declspecs, raises /* When does this happen? */ my_friendly_assert (init == NULL_TREE, 193); } - finish_decl (value, init, asmspec_tree, 1); + if (asmspec) + { + /* This must override the asm specifier which was placed + by grokclassfn. Lay this out fresh. */ + DECL_RTL (value) = NULL_RTX; + DECL_ASSEMBLER_NAME (value) = get_identifier (asmspec); + } + cp_finish_decl (value, init, asmspec_tree, 1, flags); /* Pass friends back this way. */ if (DECL_FRIEND_P (value)) @@ -1410,7 +1582,8 @@ tree grokbitfield (declarator, declspecs, width) tree declarator, declspecs, width; { - register tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, NULL_TREE); + register tree value = grokdeclarator (declarator, declspecs, BITFIELD, + 0, NULL_TREE, NULL_TREE); if (! value) return NULL_TREE; /* friends went bad. */ @@ -1444,7 +1617,7 @@ grokbitfield (declarator, declspecs, wid cp_error ("static member `%D' cannot be a bitfield", value); return NULL_TREE; } - finish_decl (value, NULL_TREE, NULL_TREE, 0); + cp_finish_decl (value, NULL_TREE, NULL_TREE, 0, 0); if (width != error_mark_node) { @@ -1613,7 +1786,7 @@ groktypefield (declspecs, parmlist) found: decl = grokdeclarator (build_parse_node (CALL_EXPR, type_id, parmlist, NULL_TREE), - declspecs, FIELD, 0, NULL_TREE); + declspecs, FIELD, 0, NULL_TREE, NULL_TREE); if (decl == NULL_TREE) return NULL_TREE; @@ -1636,7 +1809,7 @@ groktypefield (declspecs, parmlist) return void_type_node; } - finish_decl (decl, NULL_TREE, NULL_TREE, 0); + cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0, 0); /* If this declaration is common to another declaration complain about such redundancy, and return NULL_TREE @@ -1656,7 +1829,8 @@ tree grokoptypename (declspecs, declarator) tree declspecs, declarator; { - tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE); + tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, + NULL_TREE, NULL_TREE); return build_typename_overload (t); } @@ -1823,18 +1997,27 @@ build_push_scope (cname, name) return rval; /* We do need to push the scope in this case, since CTYPE helps - determine subsequent intializers (i.e., Foo::Bar x = foo_enum_1;). */ + determine subsequent initializers (i.e., Foo::Bar x = foo_enum_1;). */ push_nested_class (ctype, 3); TREE_COMPLEXITY (rval) = current_class_depth; return rval; } -void cplus_decl_attributes (decl, attributes) - tree decl, attributes; +void +cplus_decl_attributes (decl, attributes, prefix_attributes) + tree decl, attributes, prefix_attributes; { - if (decl && decl != void_type_node) - decl_attributes (decl, attributes); + if (decl == NULL_TREE || decl == void_type_node) + return; + + if (TREE_CODE (decl) == TEMPLATE_DECL) + decl = DECL_TEMPLATE_RESULT (decl); + + decl_attributes (decl, attributes, prefix_attributes); + + if (TREE_CODE (decl) == TYPE_DECL) + SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (decl), TREE_TYPE (decl)); } /* CONSTRUCTOR_NAME: @@ -1887,64 +2070,11 @@ constructor_name (thing) void setup_vtbl_ptr () { - extern rtx base_init_insns; + extern tree base_init_expr; - if (base_init_insns == 0 + if (base_init_expr == 0 && DECL_CONSTRUCTOR_P (current_function_decl)) emit_base_init (current_class_type, 0); - -#if 0 - /* This has something a little wrong with it. - - On a sun4, code like: - - be L6 - ld [%i0],%o1 - - is generated, when the below is used when -O4 is given. The delay - slot it filled with an instruction that is safe, when this isn't - used, like in: - - be L6 - sethi %hi(LC1),%o0 - ld [%i0],%o1 - - on code like: - - struct A { - virtual void print() { printf("xxx"); } - void f(); - }; - - void A::f() { - if (this) { - print(); - } else { - printf("0"); - } - } - - And that is why this is disabled for now. (mrs) - */ - - if ((flag_this_is_variable & 1) == 0 - && optimize - && current_class_type - && CLASSTYPE_VSIZE (current_class_type) - && ! DECL_STATIC_FUNCTION_P (current_function_decl)) - { - tree vfield = build_vfield_ref (C_C_D, current_class_type); - current_vtable_decl = CLASSTYPE_VTBL_PTR (current_class_type); - DECL_RTL (current_vtable_decl) = 0; - DECL_INITIAL (current_vtable_decl) = error_mark_node; - /* Have to cast the initializer, since it may have come from a - more base class then we ascribe CURRENT_VTABLE_DECL to be. */ - finish_decl (current_vtable_decl, convert_force (TREE_TYPE (current_vtable_decl), vfield), 0, 0); - current_vtable_decl = build_indirect_ref (current_vtable_decl, NULL_PTR); - } - else -#endif - current_vtable_decl = NULL_TREE; } /* Record the existence of an addressable inline function. */ @@ -1952,9 +2082,12 @@ void mark_inline_for_output (decl) tree decl; { + decl = DECL_MAIN_VARIANT (decl); if (DECL_SAVED_INLINE (decl)) return; + my_friendly_assert (TREE_PERMANENT (decl), 363); DECL_SAVED_INLINE (decl) = 1; +#if 0 if (DECL_PENDING_INLINE_INFO (decl) != 0 && ! DECL_PENDING_INLINE_INFO (decl)->deja_vu) { @@ -1974,6 +2107,7 @@ mark_inline_for_output (decl) } DECL_PENDING_INLINE_INFO (decl) = 0; } +#endif saved_inlines = perm_tree_cons (NULL_TREE, decl, saved_inlines); } @@ -1997,7 +2131,7 @@ get_temp_name (type, staticp) { char buf[sizeof (AUTO_TEMP_FORMAT) + 20]; tree decl; - int toplev = global_bindings_p (); + int toplev = toplevel_bindings_p (); push_obstacks_nochange (); if (toplev || staticp) @@ -2098,6 +2232,11 @@ finish_anon_union (anon_union_decl) if (TREE_CODE (field) != FIELD_DECL) continue; + if (TREE_PRIVATE (field)) + cp_pedwarn_at ("private member `%#D' in anonymous union", field); + else if (TREE_PROTECTED (field)) + cp_pedwarn_at ("protected member `%#D' in anonymous union", field); + decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field)); /* tell `pushdecl' that this is not tentative. */ DECL_INITIAL (decl) = error_mark_node; @@ -2109,7 +2248,8 @@ finish_anon_union (anon_union_decl) /* Only write out one anon union element--choose the one that can hold them all. */ if (main_decl == NULL_TREE - && simple_cst_equal (DECL_SIZE (decl), DECL_SIZE (anon_union_decl))) + && 1 == simple_cst_equal (DECL_SIZE (decl), + DECL_SIZE (anon_union_decl))) { main_decl = decl; } @@ -2130,7 +2270,7 @@ finish_anon_union (anon_union_decl) { if (main_decl) { - make_decl_rtl (main_decl, 0, global_bindings_p ()); + make_decl_rtl (main_decl, 0, toplevel_bindings_p ()); DECL_RTL (anon_union_decl) = DECL_RTL (main_decl); } else @@ -2170,7 +2310,9 @@ finish_table (name, type, init, publicp) if (TREE_VALUE (init) == integer_zero_node && TREE_CHAIN (init) == NULL_TREE) { +#if 0 if (empty_table == NULL_TREE) +#endif { empty_table = get_temp_name (atype, 1); init = build (CONSTRUCTOR, atype, NULL_TREE, init); @@ -2179,7 +2321,7 @@ finish_table (name, type, init, publicp) DECL_INITIAL (empty_table) = init; asmspec = build_string (IDENTIFIER_LENGTH (DECL_NAME (empty_table)), IDENTIFIER_POINTER (DECL_NAME (empty_table))); - finish_decl (empty_table, init, asmspec, 0); + cp_finish_decl (empty_table, NULL_TREE, asmspec, 0, 0); } is_empty = 1; } @@ -2217,7 +2359,7 @@ finish_table (name, type, init, publicp) IDENTIFIER_POINTER (DECL_NAME (empty_table))); } - finish_decl (decl, init, asmspec, 0); + cp_finish_decl (decl, NULL_TREE, asmspec, 0, 0); return decl; } @@ -2345,10 +2487,9 @@ static void mark_vtable_entries (decl) tree decl; { - tree entries = TREE_CHAIN (CONSTRUCTOR_ELTS (DECL_INITIAL (decl))); + tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl)); - if (flag_dossier) - entries = TREE_CHAIN (entries); + skip_rtti_stuff (&entries); for (; entries; entries = TREE_CHAIN (entries)) { @@ -2360,35 +2501,78 @@ mark_vtable_entries (decl) extern tree abort_fndecl; if (flag_vtable_thunks) fnaddr = TREE_VALUE (entries); - TREE_OPERAND (fnaddr, 0) = abort_fndecl; + TREE_OPERAND (fnaddr, 0) = fn = abort_fndecl; } + assemble_external (fn); } } -/* Set TREE_PUBLIC and/or TREE_EXTERN on the vtable DECL, +/* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL, based on TYPE and other static flags. Note that anything public is tagged TREE_PUBLIC, whether it's public in this file or in another one. */ void -import_export_vtable (decl, type) - tree decl, type; +import_export_vtable (decl, type, final) + tree decl, type; + int final; { - if (write_virtuals >= 2 - || CLASSTYPE_TEMPLATE_INSTANTIATION (type)) - { - if (CLASSTYPE_INTERFACE_KNOWN (type)) - { - TREE_PUBLIC (decl) = 1; - DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type); - } - } - else if (write_virtuals != 0) + if (DECL_INTERFACE_KNOWN (decl)) + return; + + /* +e0 or +e1 */ + if (write_virtuals < 2 && write_virtuals != 0) { TREE_PUBLIC (decl) = 1; if (write_virtuals < 0) DECL_EXTERNAL (decl) = 1; + DECL_INTERFACE_KNOWN (decl) = 1; + } + else if (CLASSTYPE_INTERFACE_KNOWN (type)) + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type); + DECL_INTERFACE_KNOWN (decl) = 1; + } + else + { + /* We can only wait to decide if we have real non-inline virtual + functions in our class, or if we come from a template. */ + + int found = CLASSTYPE_TEMPLATE_INSTANTIATION (type); + + if (! found && ! final) + { + tree method; + for (method = CLASSTYPE_METHODS (type); method != NULL_TREE; + method = DECL_NEXT_METHOD (method)) + if (DECL_VINDEX (method) != NULL_TREE + && ! DECL_THIS_INLINE (method) + && ! DECL_ABSTRACT_VIRTUAL_P (method)) + { + found = 1; + break; + } + } + + if (final || ! found) + { +#ifdef ASSEMBLE_EXTERNAL + if (TREE_PUBLIC (decl)) + cp_error ("all virtual functions redeclared inline"); +#endif + if (SUPPORTS_WEAK) + DECL_WEAK (decl) = 1; + else + TREE_PUBLIC (decl) = 0; + DECL_EXTERNAL (decl) = 0; + } + else + { + TREE_PUBLIC (decl) = 1; + DECL_EXTERNAL (decl) = 1; + } } } @@ -2407,51 +2591,68 @@ import_export_template (type) } static void -finish_vtable_vardecl (prev, vars) +finish_prevtable_vardecl (prev, vars) tree prev, vars; { tree ctype = DECL_CONTEXT (vars); import_export_template (ctype); - import_export_vtable (vars, ctype); - if (flag_vtable_thunks && !CLASSTYPE_INTERFACE_KNOWN (ctype)) + if (CLASSTYPE_INTERFACE_UNKNOWN (ctype) && TYPE_VIRTUAL_P (ctype) + && ! CLASSTYPE_TEMPLATE_INSTANTIATION (ctype)) { tree method; for (method = CLASSTYPE_METHODS (ctype); method != NULL_TREE; method = DECL_NEXT_METHOD (method)) { - if (DECL_VINDEX (method) != NULL_TREE && !DECL_SAVED_INSNS (method) + if (DECL_VINDEX (method) != NULL_TREE + && !DECL_THIS_INLINE (method) && !DECL_ABSTRACT_VIRTUAL_P (method)) { SET_CLASSTYPE_INTERFACE_KNOWN (ctype); + CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = ! DECL_EXTERNAL (method); CLASSTYPE_INTERFACE_ONLY (ctype) = DECL_EXTERNAL (method); - TREE_PUBLIC (vars) = 1; - DECL_EXTERNAL (vars) = DECL_EXTERNAL (method); break; } } } + import_export_vtable (vars, ctype, 1); + + /* We cannot use TREE_USED here, as it may be set by the expanding of a + ctor that is used to build a global object. The long term plan is to + make the TD entries statically initialized and move this to + finish_vtable_vardecl time. */ + if (flag_rtti && write_virtuals >= 0 + && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || 1 || TREE_USED (vars))) + { + /* Kick out the type descriptor before we dump out global + initializers, as they are initialized at run time and + we have to find them when we scan for things that need initialized + at the top level. */ + build_t_desc (ctype, 1); + } +} + +static void +finish_vtable_vardecl (prev, vars) + tree prev, vars; +{ if (write_virtuals >= 0 && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars))) { - extern tree the_null_vtable_entry; - - /* Stuff this virtual function table's size into - `pfn' slot of `the_null_vtable_entry'. */ - tree nelts = array_type_nelts (TREE_TYPE (vars)); - if (flag_vtable_thunks) - TREE_VALUE (CONSTRUCTOR_ELTS (DECL_INITIAL (vars))) = nelts; - else - SET_FNADDR_FROM_VTABLE_ENTRY (the_null_vtable_entry, nelts); - /* Kick out the dossier before writing out the vtable. */ - if (flag_dossier) - rest_of_decl_compilation (TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (DECL_INITIAL (vars))))), 0), 0, 1, 1); +#if 0 + /* The long term plan it to make the TD entries statically initialized, + have the entries built and emitted here. When that happens, this + can be enabled, and the other call to build_t_desc removed. */ + /* Kick out the type descriptor before writing out the vtable. */ + if (flag_rtti) + build_t_desc (DECL_CONTEXT (vars), 1); +#endif /* Write it out. */ mark_vtable_entries (vars); if (TREE_TYPE (DECL_INITIAL (vars)) == 0) - store_init_value (vars, DECL_INITIAL (vars)); + store_init_value (vars, DECL_INITIAL (vars)); #ifdef DWARF_DEBUGGING_INFO if (write_symbols == DWARF_DEBUG) @@ -2483,8 +2684,18 @@ finish_vtable_vardecl (prev, vars) rest_of_decl_compilation (vars, NULL_PTR, 1, 1); } - else if (TREE_USED (vars) && flag_vtable_thunks) - assemble_external (vars); + else if (! TREE_USED (vars)) + /* We don't know what to do with this one yet. */ + return; + + /* We know that PREV must be non-zero here. */ + TREE_CHAIN (prev) = TREE_CHAIN (vars); +} + +static void +prune_vtable_vardecl (prev, vars) + tree prev, vars; +{ /* We know that PREV must be non-zero here. */ TREE_CHAIN (prev) = TREE_CHAIN (vars); } @@ -2500,19 +2711,22 @@ walk_vtables (typedecl_fn, vardecl_fn) { register tree type = TREE_TYPE (vars); - if (TREE_CODE (vars) == TYPE_DECL - && type != error_mark_node - && TYPE_LANG_SPECIFIC (type) - && CLASSTYPE_VSIZE (type)) + if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars)) { - if (typedecl_fn) (*typedecl_fn) (prev, vars); + if (vardecl_fn) (*vardecl_fn) (prev, vars); + + if (prev && TREE_CHAIN (prev) != vars) + continue; } - else if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars)) + else if (TREE_CODE (vars) == TYPE_DECL + && type != error_mark_node + && TYPE_LANG_SPECIFIC (type) + && CLASSTYPE_VSIZE (type)) { - if (vardecl_fn) (*vardecl_fn) (prev, vars); + if (typedecl_fn) (*typedecl_fn) (prev, vars); } - else - prev = vars; + + prev = vars; } } @@ -2565,30 +2779,45 @@ void import_export_inline (decl) tree decl; { - if (TREE_PUBLIC (decl)) + if (DECL_INTERFACE_KNOWN (decl)) return; - /* If an explicit instantiation doesn't have TREE_PUBLIC set, it was with - 'extern'. */ - if (DECL_EXPLICIT_INSTANTIATION (decl) - || (DECL_IMPLICIT_INSTANTIATION (decl) && ! flag_implicit_templates)) + if (DECL_TEMPLATE_INSTANTIATION (decl)) { - TREE_PUBLIC (decl) = 1; - DECL_EXTERNAL (decl) = 1; + if (DECL_IMPLICIT_INSTANTIATION (decl) && flag_implicit_templates) + { + if (SUPPORTS_WEAK) + DECL_WEAK (decl) = 1; + else + TREE_PUBLIC (decl) = 0; + } + else + DECL_NOT_REALLY_EXTERN (decl) = 0; } else if (DECL_FUNCTION_MEMBER_P (decl)) { tree ctype = DECL_CLASS_CONTEXT (decl); - if (CLASSTYPE_INTERFACE_KNOWN (ctype)) + if (CLASSTYPE_INTERFACE_KNOWN (ctype) && ! DECL_ARTIFICIAL (decl)) { - TREE_PUBLIC (decl) = 1; - DECL_EXTERNAL (decl) - = (CLASSTYPE_INTERFACE_ONLY (ctype) - || (DECL_INLINE (decl) && ! flag_implement_inlines)); + DECL_NOT_REALLY_EXTERN (decl) + = ! (CLASSTYPE_INTERFACE_ONLY (ctype) + || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines)); } + else if (SUPPORTS_WEAK) + DECL_WEAK (decl) = 1; + else + TREE_PUBLIC (decl) = 0; } + else if (DECL_C_STATIC (decl)) + TREE_PUBLIC (decl) = 0; + else if (SUPPORTS_WEAK) + DECL_WEAK (decl) = 1; + else + TREE_PUBLIC (decl) = 0; + + DECL_INTERFACE_KNOWN (decl) = 1; } - + extern int parse_time, varconst_time; #define TIMEVAR(VAR, BODY) \ @@ -2606,9 +2835,8 @@ finish_file () int start_time, this_time; tree fnname; - tree vars = static_aggregates; + tree vars; int needs_cleaning = 0, needs_messing_up = 0; - int have_exception_handlers = build_exception_table (); if (flag_detailed_statistics) dump_tree_statistics (); @@ -2623,10 +2851,48 @@ finish_file () we'll need here. */ push_lang_context (lang_name_c); - /* Set up the name of the file-level functions we may need. */ - /* Use a global object (which is already required to be unique over - the program) rather than the file name (which imposes extra - constraints). -- Raeburn@MIT.EDU, 10 Jan 1990. */ + /* Otherwise, GDB can get confused, because in only knows + about source for LINENO-1 lines. */ + lineno -= 1; + + interface_unknown = 1; + interface_only = 0; + +#if 1 + /* The reason for pushing garbage onto the global_binding_level is to + ensure that we can slice out _DECLs which pertain to virtual function + tables. If the last thing pushed onto the global_binding_level was a + virtual function table, then slicing it out would slice away all the + decls (i.e., we lose the head of the chain). + + There are several ways of getting the same effect, from changing the + way that iterators over the chain treat the elements that pertain to + virtual function tables, moving the implementation of this code to + decl.c (where we can manipulate global_binding_level directly), + popping the garbage after pushing it and slicing away the vtable + stuff, or just leaving it alone. */ + + /* Make last thing in global scope not be a virtual function table. */ +#if 0 /* not yet, should get fixed properly later */ + vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node); +#else + vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node); +#endif + DECL_IGNORED_P (vars) = 1; + SET_DECL_ARTIFICIAL (vars); + pushdecl (vars); +#endif + + /* Walk to mark the inline functions we need, then output them so + that we can pick up any other tdecls that those routines need. */ + walk_vtables ((void (*)())0, finish_prevtable_vardecl); + + vars = static_aggregates; + + if (static_ctors || vars || might_have_exceptions_p ()) + needs_messing_up = 1; + if (static_dtors) + needs_cleaning = 1; /* See if we really need the hassle. */ while (vars && needs_cleaning == 0) @@ -2643,15 +2909,15 @@ finish_file () needs_messing_up |= TYPE_NEEDS_CONSTRUCTING (type); vars = TREE_CHAIN (vars); } + if (needs_cleaning == 0) goto mess_up; - /* Otherwise, GDB can get confused, because in only knows - about source for LINENO-1 lines. */ - lineno -= 1; - fnname = get_file_function_name ('D'); - start_function (void_list_node, build_parse_node (CALL_EXPR, fnname, void_list_node, NULL_TREE), 0, 0); + start_function (void_list_node, + build_parse_node (CALL_EXPR, fnname, void_list_node, + NULL_TREE), + NULL_TREE, NULL_TREE, 0); fnname = DECL_ASSEMBLER_NAME (current_function_decl); store_parm_decls (); @@ -2662,7 +2928,7 @@ finish_file () /* These must be done in backward order to destroy, in which they happen to be! */ - while (vars) + for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars)) { tree decl = TREE_VALUE (vars); tree type = TREE_TYPE (decl); @@ -2677,7 +2943,7 @@ finish_file () else { mark_addressable (decl); - temp = build1 (ADDR_EXPR, TYPE_POINTER_TO (type), decl); + temp = build1 (ADDR_EXPR, build_pointer_type (type), decl); } temp = build_delete (TREE_TYPE (temp), temp, integer_two_node, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); @@ -2686,14 +2952,17 @@ finish_file () if (TREE_STATIC (vars)) expand_end_cond (); } - vars = TREE_CHAIN (vars); } + for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors)) + expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors), + NULL_TREE)); + expand_end_bindings (getdecls(), 1, 0); poplevel (1, 0, 0); pop_momentary (); - finish_function (lineno, 0); + finish_function (lineno, 0, 0); assemble_destructor (IDENTIFIER_POINTER (fnname)); @@ -2702,10 +2971,13 @@ finish_file () mess_up: /* Must do this while we think we are at the top level. */ vars = nreverse (static_aggregates); - if (vars != NULL_TREE || have_exception_handlers) + if (needs_messing_up) { fnname = get_file_function_name ('I'); - start_function (void_list_node, build_parse_node (CALL_EXPR, fnname, void_list_node, NULL_TREE), 0, 0); + start_function (void_list_node, + build_parse_node (CALL_EXPR, fnname, + void_list_node, NULL_TREE), + NULL_TREE, NULL_TREE, 0); fnname = DECL_ASSEMBLER_NAME (current_function_decl); store_parm_decls (); @@ -2714,7 +2986,7 @@ finish_file () push_momentary (); expand_start_bindings (0); - if (have_exception_handlers) + if (might_have_exceptions_p ()) register_exception_table (); while (vars) @@ -2743,46 +3015,13 @@ finish_file () emit_note (input_filename, lineno); /* 9.5p5: The initializer of a static member of a class has - the same acess rights as a member function. */ + the same access rights as a member function. */ DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl); + DECL_STATIC_FUNCTION_P (current_function_decl) = 1; - if (init) - { - if (TREE_CODE (init) == VAR_DECL) - { - /* This behavior results when there are - multiple declarations of an aggregate, - the last of which defines it. */ - if (DECL_RTL (init) == DECL_RTL (decl)) - { - my_friendly_assert (DECL_INITIAL (decl) == error_mark_node - || (TREE_CODE (DECL_INITIAL (decl)) == CONSTRUCTOR - && CONSTRUCTOR_ELTS (DECL_INITIAL (decl)) == NULL_TREE), - 199); - init = DECL_INITIAL (init); - if (TREE_CODE (init) == CONSTRUCTOR - && CONSTRUCTOR_ELTS (init) == NULL_TREE) - init = NULL_TREE; - } -#if 0 - else if (TREE_TYPE (decl) == TREE_TYPE (init)) - { -#if 1 - my_friendly_abort (200); -#else - /* point to real decl's rtl anyway. */ - DECL_RTL (init) = DECL_RTL (decl); - my_friendly_assert (DECL_INITIAL (decl) == error_mark_node, - 201); - init = DECL_INITIAL (init); -#endif /* 1 */ - } -#endif /* 0 */ - } - } if (IS_AGGR_TYPE (TREE_TYPE (decl)) || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - expand_aggr_init (decl, init, 0); + expand_aggr_init (decl, init, 0, 0); else if (TREE_CODE (init) == TREE_VEC) { expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0), @@ -2803,7 +3042,16 @@ finish_file () /* a `new' expression at top level. */ expand_expr (decl, const0_rtx, VOIDmode, 0); free_temp_slots (); - expand_aggr_init (build_indirect_ref (decl, NULL_PTR), init, 0); + if (TREE_CODE (init) == TREE_VEC) + { + expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0), + TREE_VEC_ELT (init, 1), + TREE_VEC_ELT (init, 2), 0), + const0_rtx, VOIDmode, 0); + free_temp_slots (); + } + else + expand_aggr_init (build_indirect_ref (decl, NULL_PTR), init, 0, 0); } } else if (decl == error_mark_node) @@ -2814,14 +3062,22 @@ finish_file () expand_cleanups_to (old_cleanups); } + for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors)) + expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors), + NULL_TREE)); + expand_end_bindings (getdecls(), 1, 0); poplevel (1, 0, 0); pop_momentary (); - finish_function (lineno, 0); + finish_function (lineno, 0, 0); assemble_constructor (IDENTIFIER_POINTER (fnname)); } + expand_builtin_throw (); + + permanent_allocation (1); + /* Done with C language context needs. */ pop_lang_context (); @@ -2843,106 +3099,109 @@ finish_file () start_time = get_run_time (); - /* Now delete from the chain of variables all virtual function tables. - We output them all ourselves, because each will be treated specially. */ - -#if 1 - /* The reason for pushing garbage onto the global_binding_level is to - ensure that we can slice out _DECLs which pertain to virtual function - tables. If the last thing pushed onto the global_binding_level was a - virtual function table, then slicing it out would slice away all the - decls (i.e., we lose the head of the chain). - - There are several ways of getting the same effect, from changing the - way that iterators over the chain treat the elements that pertain to - virtual function tables, moving the implementation of this code to - decl.c (where we can manipulate global_binding_level directly), - popping the garbage after pushing it and slicing away the vtable - stuff, or just leaving it alone. */ - - /* Make last thing in global scope not be a virtual function table. */ -#if 0 /* not yet, should get fixed properly later */ - vars = make_type_decl (get_identifier (" @%$#@!"), integer_type_node); -#else - vars = build_decl (TYPE_DECL, get_identifier (" @%$#@!"), integer_type_node); -#endif - DECL_IGNORED_P (vars) = 1; - SET_DECL_ARTIFICIAL (vars); - pushdecl (vars); -#endif - - walk_vtables ((void (*)())0, finish_vtable_vardecl); if (flag_handle_signatures) walk_sigtables ((void (*)())0, finish_sigtable_vardecl); - for (vars = getdecls (); vars; vars = TREE_CHAIN (vars)) + for (fnname = saved_inlines; fnname; fnname = TREE_CHAIN (fnname)) { - if (TREE_CODE (vars) == THUNK_DECL) - emit_thunk (vars); + tree decl = TREE_VALUE (fnname); + import_export_inline (decl); + if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) + && TREE_PUBLIC (decl) && ! DECL_WEAK (decl) + && DECL_NOT_REALLY_EXTERN (decl)) + synthesize_method (decl); } + /* Now write out inline functions which had their addresses taken and + which were not declared virtual and which were not declared `extern + inline'. */ { - int reconsider = 0; /* More may be referenced; check again */ - tree delayed = NULL_TREE; /* These might be referenced later */ + int reconsider = 1; /* More may be referenced; check again */ - /* Now write out inline functions which had their addresses taken and - which were not declared virtual and which were not declared `extern - inline'. */ - while (saved_inlines) + while (reconsider) { - tree decl = TREE_VALUE (saved_inlines); - saved_inlines = TREE_CHAIN (saved_inlines); - /* Redefinition of a member function can cause DECL_SAVED_INSNS to be - 0; don't crash. */ - if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0) - continue; - import_export_inline (decl); - if (TREE_PUBLIC (decl) - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - || flag_keep_inline_functions) + tree last = saved_inlines = tree_cons (NULL_TREE, NULL_TREE, + saved_inlines); + tree last_head = last; + tree place = TREE_CHAIN (saved_inlines); + reconsider = 0; + + walk_vtables ((void (*)())0, finish_vtable_vardecl); + + for (; place; place = TREE_CHAIN (place)) { - if (DECL_EXTERNAL (decl)) - assemble_external (decl); - else + tree decl = TREE_VALUE (place); + + /* Slice out the empty elements put in just above in the + previous reconsidering. */ + if (decl == NULL_TREE) { - reconsider = 1; - temporary_allocation (); - output_inline_function (decl); - permanent_allocation (1); + TREE_CHAIN (last) = TREE_CHAIN (place); + continue; } - } - else if (TREE_USED (decl) - || TREE_USED (DECL_ASSEMBLER_NAME (decl))) - delayed = tree_cons (NULL_TREE, decl, delayed); - } - if (reconsider && delayed) - { - while (reconsider) - { - tree place; - reconsider = 0; - for (place = delayed; place; place = TREE_CHAIN (place)) + if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)) { - tree decl = TREE_VALUE (place); - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - && ! TREE_ASM_WRITTEN (decl)) + if (TREE_USED (decl)) + { + synthesize_method (decl); + if (TREE_ASM_WRITTEN (decl)) + reconsider = 1; + } + else { - if (DECL_EXTERNAL (decl)) - assemble_external (decl); - else - { - reconsider = 1; - temporary_allocation (); - output_inline_function (decl); - permanent_allocation (1); - } + last = place; + continue; } } + + if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0) + { + TREE_CHAIN (last) = TREE_CHAIN (place); + continue; + } + + if ((TREE_PUBLIC (decl) && ! DECL_WEAK (decl)) + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) + || flag_keep_inline_functions) + { + TREE_CHAIN (last) = TREE_CHAIN (place); + + if (DECL_NOT_REALLY_EXTERN (decl)) + { + DECL_EXTERNAL (decl) = 0; + reconsider = 1; + temporary_allocation (); + output_inline_function (decl); + permanent_allocation (1); + } + + continue; + } + + last = place; } } } + /* Now delete from the chain of variables all virtual function tables. + We output them all ourselves, because each will be treated specially. */ + + walk_vtables ((void (*)())0, prune_vtable_vardecl); + + for (vars = getdecls (); vars; vars = TREE_CHAIN (vars)) + { + if (TREE_CODE (vars) == THUNK_DECL) + emit_thunk (vars); + else if (TREE_CODE (vars) == FUNCTION_DECL + && ! DECL_INTERFACE_KNOWN (vars) + && DECL_C_STATIC (vars)) + TREE_PUBLIC (vars) = 0; + } + + if (might_have_exceptions_p ()) + emit_exception_table (); + if (write_virtuals == 2) { /* Now complain about an virtual function tables promised @@ -2956,7 +3215,8 @@ finish_file () } } - permanent_allocation (1); + finish_repo (); + this_time = get_run_time (); parse_time -= this_time - start_time; varconst_time += this_time - start_time; @@ -3029,7 +3289,7 @@ reparse_absdcl_as_casts (decl, expr) { type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1))); decl = TREE_OPERAND (decl, 0); - expr = build_c_cast (type, expr); + expr = build_c_cast (type, expr, 0); } return expr; @@ -3075,8 +3335,11 @@ tree reparse_decl_as_expr (type, decl) tree type, decl; { - decl = build_tree_list (NULL_TREE, reparse_decl_as_expr1 (decl)); - return build_functional_cast (type, decl); + decl = reparse_decl_as_expr1 (decl); + if (type) + return build_functional_cast (type, build_tree_list (NULL_TREE, decl)); + else + return decl; } /* This is something of the form `int (*a)' that has turned out to be a @@ -3154,3 +3417,99 @@ check_cp_case_value (value) return value; } + +tree current_namespace; + +/* Get the inner part of a namespace id. It doesn't have any prefix, nor + postfix. Returns 0 if in global namespace. */ +tree +get_namespace_id () +{ + tree x = current_namespace; + if (x) + x = TREE_PURPOSE (x); + return x; +} + +/* Build up a DECL_ASSEMBLER_NAME for NAME in the current namespace. */ +tree +current_namespace_id (name) + tree name; +{ + tree old_id = get_namespace_id (); + char *buf; + + /* Global names retain old encoding. */ + if (! old_id) + return name; + + buf = (char *) alloca (8 + IDENTIFIER_LENGTH (old_id) + + IDENTIFIER_LENGTH (name)); + sprintf (buf, "__ns_%s_%s", IDENTIFIER_POINTER (old_id), + IDENTIFIER_POINTER (name)); + return get_identifier (buf); +} + +void +do_namespace_alias (alias, namespace) + tree alias, namespace; +{ +} + +tree +do_toplevel_using_decl (decl) + tree decl; +{ + if (decl == NULL_TREE || decl == error_mark_node) + return; + + if (TREE_CODE (decl) == SCOPE_REF) + decl = resolve_scope_to_name (NULL_TREE, decl); + + /* Is this the right way to do an id list? */ + if (TREE_CODE (decl) != TREE_LIST) + { + pushdecl (decl); + } + else + while (decl) + { + pushdecl (TREE_VALUE (decl)); + decl = TREE_CHAIN (decl); + } +} + +tree +do_class_using_decl (decl) + tree decl; +{ + tree type; + + /* Ignore for now, unimplemented. */ + return NULL_TREE; +} + +void +do_using_directive (namespace) + tree namespace; +{ +} + +void +check_default_args (x) + tree x; +{ + tree arg = TYPE_ARG_TYPES (TREE_TYPE (x)); + int saw_def = 0, i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE); + for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i) + { + if (TREE_PURPOSE (arg)) + saw_def = 1; + else if (saw_def) + { + cp_error ("default argument missing for parameter %P of `%#D'", + i, x); + break; + } + } +}