diff options
author | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-04-22 23:13:12 +0000 |
---|---|---|
committer | mmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-04-22 23:13:12 +0000 |
commit | cec1f6a6d37512600d8592206ad4f4cb5e89231a (patch) | |
tree | e4a00a2291e86f7c0c50315f152fd043cb14bdad | |
parent | a84da62d098beef3830f994f39662b52b72f167d (diff) | |
download | gcc-cec1f6a6d37512600d8592206ad4f4cb5e89231a.tar.gz |
* cp-tree.h (lang_decl_flags): Remove returns_first_arg and
preserves_first_arg. Enlarge dummy accordingly.
(DECL_TINFO_FN_P): New macro.
(SET_DECL_TINO_FN_P): Likeiwse.
(DECL_RETURNS_FIRST_ARG): Remove.
(DECL_PRESERVES_THIS): Likewise.
(DECL_INIT_PRIORITY): New macro.
(finish_struct_1): Change prototype.
(cat_namespace_levels): Remove prototype.
(vtable_decl_p): New prototype.
(vtype_decl_p): Likewise.
(sigtable_decl_p): Likewise.
(walk_globals_pred): New typedef.
(walk_globals_fn): Likewise.
(walk_globals): New prototype.
(walk_namespaces_fn): New typedef.
(walk_namespaces): New prototype.
(wrapup_globals_for_namespace): Likewise.
(walk_vtables): Remove prototype.
(walk_sigtables): Likewise.
(instantiate_pending_templates): New prototype.
* class.c (finish_struct_1): Don't return a value.
* decl.h (pending_statics): Remove declaration.
* decl.c (walk_namespaces_r): New function.
(walk_globals_r): Likewise.
(vtable_decl_p): Likewise.
(vtype_decl_p): Likewise.
(sigtable_decl_p): Likewise.
(walk_namespaces): Likewise.
(walk_globals_data): New type.
(walk_globals): New function.
(wrapup_globals_for_namespace): Likewise.
(expand_static_init): Remove assertion. Remove redundancy in
conditional. Don't put static data members in static_aggregates
Tidy.
(finish_function): Remove redundancy in conditional. Don't set
DECL_RETURNS_FIRST_ARG.
(cat_namespace_levels): Remove.
* decl2.c: Include splay-tree.h and varray.h.
(priority_info_s): New structure.
(finish_vtable_vardecl): Change prototype. Adjust for new calling
conventions.
(prune_vtable_vardecl): Likewise.
(finish_sigtable_vardecl): Likewise.
(setup_initp): Remove.
(do_dtors): Remove.
(do_ctors): Remove.
(start_static_storage_duration_function): New function.
(generate_inits_for_priority): Likewise.
(finish_static_storage_duration_function): Likewise.
(get_priority_info): Likewise.
(do_static_initialization): Likewise.
(do_static_destruction): Likewise.
(do_static_initialization_and_destruction): Likewise.
(generate_ctor_or_dtor_function): Likewise.
(generate_ctor_and_dtor_functions_for_priority): Likewise.
(pending_statics): Make it a varray.
(pending_statics_used): New variable.
(saved_inlines): Make it a varray.
(saved_inlines_used): New variable.
(finish_static_data_member): Change method of updating
pending_statics.
(mark_inline_for_output): Remove #if 0'd code. Change method of
updating saved_inlines.
(walk_vtables): Remove.
(walk_sigtables): Likewise.
(import_export_decl): Use DECL_TINFO_FN_P.
(pending_templates): Remove declaration.
(maybe_templates): Likewise.
(static_aggregates_initp): Likewise.
(setup_initp): Likewise.
(finish_objects): Simplify.
(INITIALIZE_P_IDENTIFIER): New macro.
(PRIORITY_IDENTIFIER): New macro.
(SSDF_IDENTIFIER): New macro.
(initialize_p_decl): New variable.
(priority_decl): Likewise.
(ssdf_decl): Likewise.
(priority_info_map): Likewise.
(finish_file): Recode output of static intializers and other
file-scope finalization tasks.
* error.c (OB_END_TEMPLATE_ID): New macro.
(dump_type_real): Use it.
(dump_decl): Likewise.
(dump_function_name): Likewise.
* lex.c (set_typedecl_interface_info): Adjust for new walk_globals
interface.
(check_newline): Use walk_globals, not walk_vtables.
* pt.c (pending_tempalte_expansions): Remove.
(set_vardecl_interface_info): Likewise.
(pending_templates): Make static.
(maybe_templates): Likewise.
(instantiate_class_template): Adjust call to finish_struct_1.
(instantiate_pending_templates): New function.
* rtti.c (get_tinfo_fn): Use SET_DECL_TINFO_FN_P.
* tree.c (static_aggregates_initp): Remove.
(cp_valid_lang_attribute): Don't use it; use DECL_INIT_PRIORITY
instead.
* Makefile.in (decl2.o): Depend on varray.h and splay-tree.h.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@26594 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/cp/ChangeLog | 100 | ||||
-rw-r--r-- | gcc/cp/Makefile.in | 3 | ||||
-rw-r--r-- | gcc/cp/class.c | 8 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 52 | ||||
-rw-r--r-- | gcc/cp/decl.c | 232 | ||||
-rw-r--r-- | gcc/cp/decl.h | 5 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 1304 | ||||
-rw-r--r-- | gcc/cp/error.c | 14 | ||||
-rw-r--r-- | gcc/cp/lex.c | 40 | ||||
-rw-r--r-- | gcc/cp/pt.c | 123 | ||||
-rw-r--r-- | gcc/cp/rtti.c | 2 | ||||
-rw-r--r-- | gcc/cp/tree.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/init12.C | 22 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/link1.C | 29 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/static8.C | 32 |
15 files changed, 1261 insertions, 715 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d8ca82308af..c517e678bf6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,105 @@ 1999-04-22 Mark Mitchell <mark@codesourcery.com> + * cp-tree.h (lang_decl_flags): Remove returns_first_arg and + preserves_first_arg. Enlarge dummy accordingly. + (DECL_TINFO_FN_P): New macro. + (SET_DECL_TINO_FN_P): Likeiwse. + (DECL_RETURNS_FIRST_ARG): Remove. + (DECL_PRESERVES_THIS): Likewise. + (DECL_INIT_PRIORITY): New macro. + (finish_struct_1): Change prototype. + (cat_namespace_levels): Remove prototype. + (vtable_decl_p): New prototype. + (vtype_decl_p): Likewise. + (sigtable_decl_p): Likewise. + (walk_globals_pred): New typedef. + (walk_globals_fn): Likewise. + (walk_globals): New prototype. + (walk_namespaces_fn): New typedef. + (walk_namespaces): New prototype. + (wrapup_globals_for_namespace): Likewise. + (walk_vtables): Remove prototype. + (walk_sigtables): Likewise. + (instantiate_pending_templates): New prototype. + * class.c (finish_struct_1): Don't return a value. + * decl.h (pending_statics): Remove declaration. + * decl.c (walk_namespaces_r): New function. + (walk_globals_r): Likewise. + (vtable_decl_p): Likewise. + (vtype_decl_p): Likewise. + (sigtable_decl_p): Likewise. + (walk_namespaces): Likewise. + (walk_globals_data): New type. + (walk_globals): New function. + (wrapup_globals_for_namespace): Likewise. + (expand_static_init): Remove assertion. Remove redundancy in + conditional. Don't put static data members in static_aggregates + Tidy. + (finish_function): Remove redundancy in conditional. Don't set + DECL_RETURNS_FIRST_ARG. + (cat_namespace_levels): Remove. + * decl2.c: Include splay-tree.h and varray.h. + (priority_info_s): New structure. + (finish_vtable_vardecl): Change prototype. Adjust for new calling + conventions. + (prune_vtable_vardecl): Likewise. + (finish_sigtable_vardecl): Likewise. + (setup_initp): Remove. + (do_dtors): Remove. + (do_ctors): Remove. + (start_static_storage_duration_function): New function. + (generate_inits_for_priority): Likewise. + (finish_static_storage_duration_function): Likewise. + (get_priority_info): Likewise. + (do_static_initialization): Likewise. + (do_static_destruction): Likewise. + (do_static_initialization_and_destruction): Likewise. + (generate_ctor_or_dtor_function): Likewise. + (generate_ctor_and_dtor_functions_for_priority): Likewise. + (pending_statics): Make it a varray. + (pending_statics_used): New variable. + (saved_inlines): Make it a varray. + (saved_inlines_used): New variable. + (finish_static_data_member): Change method of updating + pending_statics. + (mark_inline_for_output): Remove #if 0'd code. Change method of + updating saved_inlines. + (walk_vtables): Remove. + (walk_sigtables): Likewise. + (import_export_decl): Use DECL_TINFO_FN_P. + (pending_templates): Remove declaration. + (maybe_templates): Likewise. + (static_aggregates_initp): Likewise. + (setup_initp): Likewise. + (finish_objects): Simplify. + (INITIALIZE_P_IDENTIFIER): New macro. + (PRIORITY_IDENTIFIER): New macro. + (SSDF_IDENTIFIER): New macro. + (initialize_p_decl): New variable. + (priority_decl): Likewise. + (ssdf_decl): Likewise. + (priority_info_map): Likewise. + (finish_file): Recode output of static intializers and other + file-scope finalization tasks. + * error.c (OB_END_TEMPLATE_ID): New macro. + (dump_type_real): Use it. + (dump_decl): Likewise. + (dump_function_name): Likewise. + * lex.c (set_typedecl_interface_info): Adjust for new walk_globals + interface. + (check_newline): Use walk_globals, not walk_vtables. + * pt.c (pending_tempalte_expansions): Remove. + (set_vardecl_interface_info): Likewise. + (pending_templates): Make static. + (maybe_templates): Likewise. + (instantiate_class_template): Adjust call to finish_struct_1. + (instantiate_pending_templates): New function. + * rtti.c (get_tinfo_fn): Use SET_DECL_TINFO_FN_P. + * tree.c (static_aggregates_initp): Remove. + (cp_valid_lang_attribute): Don't use it; use DECL_INIT_PRIORITY + instead. + * Makefile.in (decl2.o): Depend on varray.h and splay-tree.h. + * gxx.gperf (RETURN): Rename to RETURN_KEYWORD to avoid clashes with the RTL code RETURN. * hash.h: Regenerated. diff --git a/gcc/cp/Makefile.in b/gcc/cp/Makefile.in index d806506e2c5..616525c29cf 100644 --- a/gcc/cp/Makefile.in +++ b/gcc/cp/Makefile.in @@ -261,7 +261,8 @@ decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \ $(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \ - $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h + $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h \ + $(srcdir)/../../include/splay-tree.h $(srcdir)/../varray.h typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \ $(srcdir)/../system.h $(srcdir)/../toplev.h typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \ diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 87a82c7beea..9a20b5b093f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -3099,7 +3099,7 @@ add_implicitly_declared_members (t, cant_have_default_ctor, ATTRIBUTES is the set of decl attributes to be applied, if any. */ -tree +void finish_struct_1 (t, warn_anon) tree t; int warn_anon; @@ -3144,7 +3144,7 @@ finish_struct_1 (t, warn_anon) else my_friendly_abort (172); popclass (); - return t; + return; } GNU_xref_decl (current_function_decl, t); @@ -4116,7 +4116,7 @@ finish_struct_1 (t, warn_anon) /* Finish debugging output for this type. */ rest_of_type_compilation (t, toplevel_bindings_p ()); - return t; + return; } /* When T was built up, the member declarations were added in reverse @@ -4210,7 +4210,7 @@ finish_struct (t, attributes, warn_anon) TYPE_SIZE (t) = integer_zero_node; } else - t = finish_struct_1 (t, warn_anon); + finish_struct_1 (t, warn_anon); TYPE_BEING_DEFINED (t) = 0; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b94f6f50af5..9dccb4d9331 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -88,6 +88,9 @@ Boston, MA 02111-1307, USA. */ For a TYPENAME_TYPE, this is TYPENAME_TYPE_FULLNAME. For a TEMPLATE_TEMPLATE_PARM, this is TEMPLATE_TEMPLATE_PARM_TEMPLATE_INFO. + + DECL_SAVED_INSNS/DECL_FIELD_SIZE + For a static VAR_DECL, this is DECL_INIT_PRIORITY. */ /* Language-dependent contents of an identifier. */ @@ -1149,8 +1152,6 @@ struct lang_decl_flags unsigned operator_attr : 1; unsigned constructor_attr : 1; - unsigned returns_first_arg : 1; - unsigned preserves_first_arg : 1; unsigned friend_attr : 1; unsigned static_function : 1; unsigned const_memfunc : 1; @@ -1171,7 +1172,7 @@ struct lang_decl_flags unsigned needs_final_overrider : 1; unsigned bitfield : 1; unsigned defined_in_class : 1; - unsigned dummy : 1; + unsigned dummy : 3; tree access; tree context; @@ -1221,20 +1222,20 @@ struct lang_decl for an object with virtual baseclasses. */ #define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr) +/* Non-zero for a FUNCTION_DECL that declares a type-info function. */ +#define DECL_TINFO_FN_P(NODE) \ + (TREE_CODE (NODE) == FUNCTION_DECL \ + && DECL_ARTIFICIAL (NODE) \ + && DECL_LANG_SPECIFIC(NODE)->decl_flags.mutable_flag) + +/* Mark NODE as a type-info function. */ +#define SET_DECL_TINFO_FN_P(NODE) \ + (DECL_LANG_SPECIFIC((NODE))->decl_flags.mutable_flag = 1) + /* For FUNCTION_DECLs: nonzero means that this function is a default implementation of a signature method. */ #define IS_DEFAULT_IMPLEMENTATION(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.is_default_implementation) -/* For FUNCTION_DECLs: nonzero means that the constructor - is known to return a non-zero `this' unchanged. */ -#define DECL_RETURNS_FIRST_ARG(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.returns_first_arg) - -/* Nonzero for FUNCTION_DECL means that this constructor is known to - not make any assignment to `this', and therefore can be trusted - to return it unchanged. Otherwise, we must re-assign `current_class_ptr' - after performing base initializations. */ -#define DECL_PRESERVES_THIS(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.preserves_first_arg) - /* Nonzero for _DECL means that this decl appears in (or will appear in) as a member in a RECORD_TYPE or UNION_TYPE node. It is also for detecting circularity in case members are multiply defined. In the @@ -1352,6 +1353,11 @@ struct lang_decl #define ORIGINAL_NAMESPACE(NODE) \ (DECL_NAMESPACE_ALIAS (NODE) ? DECL_NAMESPACE_ALIAS (NODE) : (NODE)) +/* In a non-local VAR_DECL with static storage duration, this is the + initialization priority. If this value is zero, the NODE will be + initialized at the DEFAULT_INIT_PRIORITY. */ +#define DECL_INIT_PRIORITY(NODE) (DECL_FIELD_SIZE ((NODE))) + /* In a TREE_LIST concatenating using directives, indicate indirekt directives */ #define TREE_INDIRECT_USING(NODE) ((NODE)->common.lang_flag_0) @@ -2715,7 +2721,7 @@ extern int currently_open_class PROTO((tree)); extern tree get_vfield_offset PROTO((tree)); extern void duplicate_tag_error PROTO((tree)); extern tree finish_struct PROTO((tree, tree, int)); -extern tree finish_struct_1 PROTO((tree, int)); +extern void finish_struct_1 PROTO((tree, int)); extern int resolves_to_fixed_type_p PROTO((tree, int *)); extern void init_class_processing PROTO((void)); extern int is_empty_class PROTO((tree)); @@ -2873,7 +2879,6 @@ extern int in_function_p PROTO((void)); extern void replace_defarg PROTO((tree, tree)); extern void print_other_binding_stack PROTO((struct binding_level *)); extern void revert_static_member_fn PROTO((tree*, tree*, tree*)); -extern void cat_namespace_levels PROTO((void)); extern void fixup_anonymous_union PROTO((tree)); extern int check_static_variable_definition PROTO((tree, tree)); extern void push_local_binding PROTO((tree, tree, int)); @@ -2882,6 +2887,18 @@ extern tree check_default_argument PROTO((tree, tree)); extern tree push_overloaded_decl PROTO((tree, int)); extern void clear_identifier_class_values PROTO((void)); extern void storetags PROTO((tree)); +extern int vtable_decl_p PROTO((tree, void *)); +extern int vtype_decl_p PROTO((tree, void *)); +extern int sigtable_decl_p PROTO((tree, void *)); +typedef int (*walk_globals_pred) PROTO((tree, void *)); +typedef int (*walk_globals_fn) PROTO((tree *, void *)); +extern int walk_globals PROTO((walk_globals_pred, + walk_globals_fn, + void *)); +typedef int (*walk_namespaces_fn) PROTO((tree, void *)); +extern int walk_namespaces PROTO((walk_namespaces_fn, + void *)); +extern int wrapup_globals_for_namespace PROTO((tree, void *)); /* in decl2.c */ extern int check_java_method PROTO((tree)); @@ -2919,10 +2936,6 @@ extern tree coerce_delete_type PROTO((tree)); extern void comdat_linkage PROTO((tree)); extern void import_export_class PROTO((tree)); extern void import_export_vtable PROTO((tree, tree, int)); -extern int walk_vtables PROTO((void (*)(tree, tree), - int (*)(tree, tree))); -extern void walk_sigtables PROTO((void (*)(tree, tree), - void (*)(tree, tree))); extern void import_export_decl PROTO((tree)); extern tree build_cleanup PROTO((tree)); extern void finish_file PROTO((void)); @@ -3158,6 +3171,7 @@ extern void maybe_process_partial_specialization PROTO((tree)); extern void maybe_check_template_type PROTO((tree)); extern tree most_specialized_instantiation PROTO((tree, tree)); extern void print_candidates PROTO((tree)); +extern int instantiate_pending_templates PROTO((void)); extern int processing_specialization; extern int processing_explicit_instantiation; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 917535a0164..5457e9216c3 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -192,6 +192,8 @@ static void find_class_binding_level PROTO((void)); static struct binding_level *innermost_nonclass_level PROTO((void)); static tree poplevel_class PROTO((void)); static void warn_about_implicit_typename_lookup PROTO((tree, tree)); +static int walk_namespaces_r PROTO((tree, walk_namespaces_fn, void *)); +static int walk_globals_r PROTO((tree, void *)); #if defined (DEBUG_CP_BINDING_LEVELS) static void indent PROTO((void)); @@ -1833,6 +1835,179 @@ clear_identifier_class_values () IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE; } +/* Returns non-zero if T is a virtual function table. */ + +int +vtable_decl_p (t, data) + tree t; + void *data ATTRIBUTE_UNUSED; +{ + return (TREE_CODE (t) == VAR_DECL && DECL_VIRTUAL_P (t)); +} + +/* Returns non-zero if T is a TYPE_DECL for a type with virtual + functions. */ + +int +vtype_decl_p (t, data) + tree t; + void *data ATTRIBUTE_UNUSED; +{ + return (TREE_CODE (t) == TYPE_DECL + && TREE_TYPE (t) != error_mark_node + && TYPE_LANG_SPECIFIC (TREE_TYPE (t)) + && CLASSTYPE_VSIZE (TREE_TYPE (t))); +} + +/* Returns non-zero if T is a signature table. */ + +int +sigtable_decl_p (t, data) + tree t; + void *data ATTRIBUTE_UNUSED; +{ + return (TREE_CODE (t) == VAR_DECL + && TREE_TYPE (t) != error_mark_node + && IS_SIGNATURE (TREE_TYPE (t))); +} + +/* Walk all the namespaces contained NAMESPACE, including NAMESPACE + itself, calling F for each. The DATA is passed to F as well. */ + +static int +walk_namespaces_r (namespace, f, data) + tree namespace; + walk_namespaces_fn f; + void *data; +{ + tree current; + int result = 0; + + result |= (*f) (namespace, data); + + for (current = NAMESPACE_LEVEL (namespace)->names; + current; + current = TREE_CHAIN (current)) + { + if (TREE_CODE (current) != NAMESPACE_DECL + || DECL_NAMESPACE_ALIAS (current)) + continue; + if (!DECL_LANG_SPECIFIC (current)) + { + /* Hmm. std. */ + my_friendly_assert (current == std_node, 393); + continue; + } + + /* We found a namespace. */ + result |= walk_namespaces_r (current, f, data); + } + + return result; +} + +/* Walk all the namespaces, calling F for each. The DATA is passed to + F as well. */ + +int +walk_namespaces (f, data) + walk_namespaces_fn f; + void *data; +{ + return walk_namespaces_r (global_namespace, f, data); +} + +struct walk_globals_data { + walk_globals_pred p; + walk_globals_fn f; + void *data; +}; + +/* Walk the global declarations in NAMESPACE. Whenever one is found + for which P returns non-zero, call F with its address. If any call + to F returns a non-zero value, return a non-zero value. */ + +static int +walk_globals_r (namespace, data) + tree namespace; + void *data; +{ + struct walk_globals_data* wgd = (struct walk_globals_data *) data; + walk_globals_pred p = wgd->p; + walk_globals_fn f = wgd->f; + void *d = wgd->data; + tree *t; + int result = 0; + + t = &NAMESPACE_LEVEL (namespace)->names; + + while (*t) + { + tree glbl = *t; + + if ((*p) (glbl, d)) + result |= (*f) (t, d); + + /* If F changed *T, then *T still points at the next item to + examine. */ + if (*t == glbl) + t = &TREE_CHAIN (*t); + } + + return result; +} + +/* Walk the global declarations. Whenever one is found for which P + returns non-zero, call F with its address. If any call to F + returns a non-zero value, return a non-zero value. */ + +int +walk_globals (p, f, data) + walk_globals_pred p; + walk_globals_fn f; + void *data; +{ + struct walk_globals_data wgd; + wgd.p = p; + wgd.f = f; + wgd.data = data; + + return walk_namespaces (walk_globals_r, &wgd); +} + +/* Call wrapup_globals_declarations for the globals in NAMESPACE. If + DATA is non-NULL, this is the last time we will call + wrapup_global_declarations for this NAMESPACE. */ + +int +wrapup_globals_for_namespace (namespace, data) + tree namespace; + void *data; +{ + tree globals = NAMESPACE_LEVEL (namespace)->names; + int len = list_length (globals); + tree *vec = (tree *) alloca (sizeof (tree) * len); + int i; + tree decl; + int last_time = (data != 0); + + if (last_time && namespace == global_namespace) + /* Let compile_file handle the global namespace. */ + return 0; + + /* Process the decls in reverse order--earliest first. + Put them into VEC from back to front, then take out from front. */ + + for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) + vec[len - i - 1] = decl; + + if (!last_time) + return wrapup_global_declarations (vec, len); + + check_global_declarations (vec, len); + return 0; +} + /* For debugging. */ static int no_print_functions = 0; @@ -2196,38 +2371,6 @@ pop_namespace () suspend_binding_level (); } -/* Concatenate the binding levels of all namespaces. */ - -void -cat_namespace_levels() -{ - tree current; - tree last; - struct binding_level *b; - - last = NAMESPACE_LEVEL (global_namespace) -> names; - /* The nested namespaces appear in the names list of their ancestors. */ - for (current = last; current; current = TREE_CHAIN (current)) - { - /* Catch simple infinite loops. */ - if (TREE_CHAIN (current) == current) - my_friendly_abort (990126); - - if (TREE_CODE (current) != NAMESPACE_DECL - || DECL_NAMESPACE_ALIAS (current)) - continue; - if (!DECL_LANG_SPECIFIC (current)) - { - /* Hmm. std. */ - my_friendly_assert (current == std_node, 393); - continue; - } - b = NAMESPACE_LEVEL (current); - while (TREE_CHAIN (last)) - last = TREE_CHAIN (last); - TREE_CHAIN (last) = NAMESPACE_LEVEL (current) -> names; - } -} /* Subroutines for reverting temporarily to top-level for instantiation of templates and such. We actually need to clear out the class- and @@ -8259,15 +8402,12 @@ expand_static_init (decl, init) { tree oldstatic = value_member (decl, static_aggregates); - /* If at_eof is 2, we're too late. */ - my_friendly_assert (at_eof <= 1, 990323); - if (oldstatic) { if (TREE_PURPOSE (oldstatic) && init != NULL_TREE) cp_error ("multiple initializations given for `%D'", decl); } - else if (! toplevel_bindings_p () && ! pseudo_global_level_p ()) + else if (! toplevel_bindings_p ()) { /* Emit code to perform this initialization but once. */ tree temp; @@ -8369,22 +8509,16 @@ expand_static_init (decl, init) } expand_end_cond (); - if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) - { - static_aggregates = perm_tree_cons (temp, decl, static_aggregates); - TREE_STATIC (static_aggregates) = 1; - } - /* Resume old (possibly temporary) allocation. */ pop_obstacks (); } else { - /* This code takes into account memory allocation - policy of `start_decl'. Namely, if TYPE_NEEDS_CONSTRUCTING - does not hold for this object, then we must make permanent - the storage currently in the temporary obstack. */ - if (! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) + /* This code takes into account memory allocation policy of + `start_decl'. Namely, if TYPE_NEEDS_CONSTRUCTING does not + hold for this object, then we must make permanent the storage + currently in the temporary obstack. */ + if (!TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) preserve_initializer (); static_aggregates = perm_tree_cons (init, decl, static_aggregates); } @@ -13758,7 +13892,7 @@ finish_function (lineno, flags, nested) if (fndecl == NULL_TREE) return; - if (! nested && function_depth > 1) + if (function_depth > 1) nested = 1; fntype = TREE_TYPE (fndecl); @@ -14029,8 +14163,6 @@ finish_function (lineno, flags, nested) tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type); CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE; - DECL_RETURNS_FIRST_ARG (fndecl) = 1; - if (flag_this_is_variable > 0) { cond = build_binary_op (EQ_EXPR, diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h index f55dca55ea7..fcb247e7020 100644 --- a/gcc/cp/decl.h +++ b/gcc/cp/decl.h @@ -42,11 +42,6 @@ extern tree this_identifier, in_charge_identifier; or a chain or parameter decls here. */ extern tree last_function_parms; -/* A list of static class variables. This is needed, because a - static class variable can be declared inside the class without - an initializer, and then initialized, staticly, outside the class. */ -extern tree pending_statics; - /* A list of objects which have constructors or destructors which reside in the global scope. The decl is stored in the TREE_VALUE slot and the initializer is stored diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ac52f6dd3d6..ea469f3ef10 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -42,35 +42,54 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "dwarf2out.h" #include "dwarfout.h" +#include "splay-tree.h" +#include "varray.h" #if USE_CPPLIB #include "cpplib.h" extern cpp_reader parse_in; #endif +/* This structure contains information about the initializations + and/or destructions required for a particular priority level. */ +typedef struct priority_info_s { + /* A label indicating where we should generate the next + initialization with this priority. */ + rtx initialization_sequence; + /* A label indicating where we should generate the next destruction + with this priority. */ + rtx destruction_sequence; +} *priority_info; + static tree get_sentry PROTO((tree)); static void mark_vtable_entries PROTO((tree)); static void grok_function_init PROTO((tree, tree)); -static int finish_vtable_vardecl PROTO((tree, tree)); -static int prune_vtable_vardecl PROTO((tree, tree)); -static void finish_sigtable_vardecl PROTO((tree, tree)); +static int finish_vtable_vardecl PROTO((tree *, void *)); +static int prune_vtable_vardecl PROTO((tree *, void *)); +static int finish_sigtable_vardecl PROTO((tree *, void *)); static int is_namespace_ancestor PROTO((tree, tree)); static void add_using_namespace PROTO((tree, tree, int)); static tree ambiguous_decl PROTO((tree, tree, tree,int)); static tree build_anon_union_vars PROTO((tree, tree*, int, int)); static int acceptable_java_type PROTO((tree)); static void output_vtable_inherit PROTO((tree)); -static void setup_initp PROTO((void)); static void start_objects PROTO((int, int)); static void finish_objects PROTO((int, int)); -static void do_dtors PROTO((tree)); -static void do_ctors PROTO((tree)); static tree merge_functions PROTO((tree, tree)); static tree decl_namespace PROTO((tree)); static tree validate_nonmember_using_decl PROTO((tree, tree *, tree *)); static void do_nonmember_using_decl PROTO((tree, tree, tree, tree, tree *, tree *)); - +static void start_static_storage_duration_function PROTO((void)); +static int generate_inits_for_priority PROTO((splay_tree_node, void *)); +static void finish_static_storage_duration_function PROTO((void)); +static priority_info get_priority_info PROTO((int)); +static void do_static_initialization PROTO((tree, tree, tree, int)); +static void do_static_destruction PROTO((tree, tree, int)); +static void do_static_initialization_and_destruction PROTO((tree, tree)); +static void generate_ctor_or_dtor_function PROTO((int, int)); +static int generate_ctor_and_dtor_functions_for_priority + PROTO((splay_tree_node, void *)); extern int current_class_depth; /* A list of virtual function tables we must make sure to write out. */ @@ -79,11 +98,13 @@ tree pending_vtables; /* A list of static class variables. This is needed, because a static class variable can be declared inside the class without an initializer, and then initialized, staticly, outside the class. */ -tree pending_statics; +static varray_type pending_statics; +static size_t pending_statics_used; /* A list of functions which were declared inline, but which we may need to emit outline anyway. */ -static tree saved_inlines; +static varray_type saved_inlines; +static size_t saved_inlines_used; /* Used to help generate temporary names which are unique within a function. Reset to 0 by start_function. */ @@ -1487,8 +1508,17 @@ finish_static_data_member_decl (decl, init, asmspec_tree, need_pop, flags) = build_static_name (current_class_type, DECL_NAME (decl)); } if (! processing_template_decl) - pending_statics = perm_tree_cons (NULL_TREE, decl, pending_statics); - + { + if (!pending_statics) + VARRAY_TREE_INIT (pending_statics, 32, "pending_statics"); + + if (pending_statics_used == pending_statics->num_elements) + VARRAY_GROW (pending_statics, + 2 * pending_statics->num_elements); + VARRAY_TREE (pending_statics, pending_statics_used) = decl; + ++pending_statics_used; + } + /* Static consts need not be initialized in the class definition. */ if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { @@ -2010,28 +2040,14 @@ mark_inline_for_output (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) - { - struct pending_inline *t = pending_inlines; - my_friendly_assert (DECL_SAVED_INSNS (decl) == 0, 198); - while (t) - { - if (t == DECL_PENDING_INLINE_INFO (decl)) - break; - t = t->next; - } - if (t == 0) - { - t = DECL_PENDING_INLINE_INFO (decl); - t->next = pending_inlines; - pending_inlines = t; - } - DECL_PENDING_INLINE_INFO (decl) = 0; - } -#endif - saved_inlines = perm_tree_cons (NULL_TREE, decl, saved_inlines); + if (!saved_inlines) + VARRAY_TREE_INIT (saved_inlines, 32, "saved_inlines"); + + if (saved_inlines_used == saved_inlines->num_elements) + VARRAY_GROW (saved_inlines, + 2 * saved_inlines->num_elements); + VARRAY_TREE (saved_inlines, saved_inlines_used) = decl; + ++saved_inlines_used; } void @@ -2625,17 +2641,17 @@ output_vtable_inherit (vars) } static int -finish_vtable_vardecl (prev, vars) - tree prev, vars; +finish_vtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; { + tree vars = *t; tree ctype = DECL_CONTEXT (vars); import_export_class (ctype); import_export_vtable (vars, ctype, 1); if (! DECL_EXTERNAL (vars) - && (DECL_INTERFACE_KNOWN (vars) - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)) - || (hack_decl_function_context (vars) && TREE_USED (vars))) + && (DECL_INTERFACE_KNOWN (vars) || TREE_USED (vars)) && ! TREE_ASM_WRITTEN (vars)) { /* Write it out. */ @@ -2680,98 +2696,35 @@ finish_vtable_vardecl (prev, vars) return 1; } - else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars))) + else if (! TREE_USED (vars)) /* We don't know what to do with this one yet. */ return 0; - /* We know that PREV must be non-zero here. */ - TREE_CHAIN (prev) = TREE_CHAIN (vars); + *t = TREE_CHAIN (vars); return 0; } static int -prune_vtable_vardecl (prev, vars) - tree prev, vars; +prune_vtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; { - /* We know that PREV must be non-zero here. */ - TREE_CHAIN (prev) = TREE_CHAIN (vars); + *t = TREE_CHAIN (*t); return 1; } -int -walk_vtables (typedecl_fn, vardecl_fn) - register void (*typedecl_fn) PROTO ((tree, tree)); - register int (*vardecl_fn) PROTO ((tree, tree)); -{ - tree prev, vars; - int flag = 0; - - for (prev = 0, vars = getdecls (); vars; vars = TREE_CHAIN (vars)) - { - register tree type = TREE_TYPE (vars); - - if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars)) - { - if (vardecl_fn) - flag |= (*vardecl_fn) (prev, vars); - - if (prev && TREE_CHAIN (prev) != vars) - continue; - } - else if (TREE_CODE (vars) == TYPE_DECL - && type != error_mark_node - && TYPE_LANG_SPECIFIC (type) - && CLASSTYPE_VSIZE (type)) - { - if (typedecl_fn) (*typedecl_fn) (prev, vars); - } - - prev = vars; - } - - return flag; -} - -static void -finish_sigtable_vardecl (prev, vars) - tree prev, vars; +static int +finish_sigtable_vardecl (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; { /* We don't need to mark sigtable entries as addressable here as is done for vtables. Since sigtables, unlike vtables, are always written out, that was already done in build_signature_table_constructor. */ - rest_of_decl_compilation (vars, NULL_PTR, 1, 1); - - /* We know that PREV must be non-zero here. */ - TREE_CHAIN (prev) = TREE_CHAIN (vars); -} - -void -walk_sigtables (typedecl_fn, vardecl_fn) - register void (*typedecl_fn) PROTO((tree, tree)); - register void (*vardecl_fn) PROTO((tree, tree)); -{ - tree prev, vars; - - for (prev = 0, vars = getdecls (); vars; vars = TREE_CHAIN (vars)) - { - register tree type = TREE_TYPE (vars); - - if (TREE_CODE (vars) == TYPE_DECL - && type != error_mark_node - && IS_SIGNATURE (type)) - { - if (typedecl_fn) (*typedecl_fn) (prev, vars); - } - else if (TREE_CODE (vars) == VAR_DECL - && TREE_TYPE (vars) != error_mark_node - && IS_SIGNATURE (TREE_TYPE (vars))) - { - if (vardecl_fn) (*vardecl_fn) (prev, vars); - } - else - prev = vars; - } + rest_of_decl_compilation (*t, NULL_PTR, 1, 1); + *t = TREE_CHAIN (*t); + return 1; } /* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an @@ -2824,8 +2777,7 @@ import_export_decl (decl) else comdat_linkage (decl); } - /* tinfo function */ - else if (DECL_ARTIFICIAL (decl) && DECL_MUTABLE_P (decl)) + else if (DECL_TINFO_FN_P (decl)) { tree ctype = TREE_TYPE (DECL_NAME (decl)); @@ -2882,8 +2834,6 @@ build_cleanup (decl) } extern int parse_time, varconst_time; -extern tree pending_templates; -extern tree maybe_templates; static tree get_sentry (base) @@ -2911,105 +2861,6 @@ get_sentry (base) return sentry; } -/* A list of objects which have constructors or destructors - which reside in the global scope. The decl is stored in - the TREE_VALUE slot and the initializer is stored - in the TREE_PURPOSE slot. */ -extern tree static_aggregates_initp; - -/* Set up the static_aggregates* lists for processing. Subroutine of - finish_file. Note that this function changes the format of - static_aggregates_initp, from (priority . decl) to - (priority . ((initializer . decl) ...)). */ - -static void -setup_initp () -{ - tree t, *p, next_t; - tree default_pri = build_int_2 (DEFAULT_INIT_PRIORITY, 0); - int saw_default; - - /* First, remove any entries from static_aggregates that are also in - static_aggregates_initp, and update the entries in _initp to include - the initializer. For entries not in static_aggregates_initp, update - them in place to look the same way. */ - p = &static_aggregates; - for (; *p; ) - { - /* We check for symbol equivalence rather than identical decls - because decl_attributes is run before duplicate_decls. - XXX change to use DECL_MACHINE_ATTRIBUTES instead of - static_aggregates_initp. */ - for (t = static_aggregates_initp; t; t = TREE_CHAIN (t)) - if (DECL_ASSEMBLER_NAME (TREE_VALUE (t)) - == DECL_ASSEMBLER_NAME (TREE_VALUE (*p))) - break; - - if (t) - { - /* We found an entry in s_a_initp; replace that entry with the - format we want and remove the entry in s_a. */ - TREE_VALUE (t) = *p; - *p = TREE_CHAIN (*p); - TREE_CHAIN (TREE_VALUE (t)) = NULL_TREE; - } - else - { - /* We didn't find an entry in s_a_i; replace the entry in s_a - with the format we want. */ - *p = perm_tree_cons (default_pri, *p, TREE_CHAIN (*p)); - TREE_CHAIN (TREE_VALUE (*p)) = NULL_TREE; - p = &TREE_CHAIN (*p); - } - } - - /* And then attach the two lists. By doing it this way, ctors with an - explicit priority equal to the default are run before ctors with no - explicit priority (i.e. the ones in s_a). */ - static_aggregates_initp = chainon (static_aggregates, - static_aggregates_initp); - static_aggregates = NULL_TREE; - - /* Then, group static_aggregates_initp. After this step, there will only - be one entry for each priority, with a chain coming off it. */ - t = static_aggregates_initp; - static_aggregates_initp = NULL_TREE; - - saw_default = 0; - for (; t; t = next_t) - { - next_t = TREE_CHAIN (t); - if (TREE_INT_CST_LOW (TREE_PURPOSE (t)) == DEFAULT_INIT_PRIORITY) - saw_default = 1; - - for (p = &static_aggregates_initp; ; p = &TREE_CHAIN (*p)) - { - if (*p == NULL_TREE - || tree_int_cst_lt (TREE_PURPOSE (*p), TREE_PURPOSE (t))) - { - TREE_CHAIN (t) = *p; - *p = t; - break; - } - else if (tree_int_cst_equal (TREE_PURPOSE (*p), TREE_PURPOSE (t))) - { - TREE_CHAIN (TREE_VALUE (t)) = TREE_VALUE (*p); - TREE_VALUE (*p) = TREE_VALUE (t); - break; - } - } - } - - if (! saw_default) - static_aggregates_initp = perm_tree_cons (default_pri, error_mark_node, - static_aggregates_initp); - - /* Reverse each list to preserve the order (currently reverse declaration - order, for destructors). */ - for (t = static_aggregates_initp; t; t = TREE_CHAIN (t)) - TREE_VALUE (t) = nreverse (TREE_VALUE (t)); -} - /* Start the process of running a particular set of global constructors or destructors. Subroutine of do_[cd]tors. */ @@ -3064,23 +2915,7 @@ static void finish_objects (method_type, initp) int method_type, initp; { - char *fnname; - - if (initp == DEFAULT_INIT_PRIORITY) - { - tree list = (method_type == 'I' ? static_ctors : static_dtors); - - if (! current_function_decl && list) - start_objects (method_type, initp); - - for (; list; list = TREE_CHAIN (list)) - expand_expr_stmt (build_function_call (TREE_VALUE (list), NULL_TREE)); - } - - if (! current_function_decl) - return; - - fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); + char *fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0); /* Finish up. */ expand_end_bindings (getdecls (), 1, 0); @@ -3115,456 +2950,719 @@ finish_objects (method_type, initp) #endif } -/* Generate a function to run a set of global destructors. START is either - NULL_TREE or a node indicating a set of destructors with the same - init priority. Subroutine of finish_file. */ +/* The names of the parameters to the function created to handle + initializations and destructions for objects with static storage + duration. */ +#define INITIALIZE_P_IDENTIFIER "__initialize_p" +#define PRIORITY_IDENTIFIER "__priority" + +/* The name of the function we create to handle initializations and + destructions for objects with static storage duration. */ +#define SSDF_IDENTIFIER "__static_initialization_and_destruction" + +/* The declaration for the __INITIALIZE_P argument. */ +static tree initialize_p_decl; + +/* The declaration for the __PRIORITY argument. */ +static tree priority_decl; + +/* The declaration for the static storage duration function. */ +static tree ssdf_decl; + +/* A map from priority levels to information about that priority + level. There may be many such levels, so efficient lookup is + important. */ +static splay_tree priority_info_map; + +/* Begins the generation of the function that will handle all + initialization and destruction of objects with static storage + duration. The function generated takes two parameters of type + `int': __INITIALIZE_P and __PRIORITY. If __INITIALIZE_P is + non-zero, it performs initializations. Otherwise, it performs + destructions. It only performs those initializations or + destructions with the indicated __PRIORITY. The generated function + returns no value. + + It is assumed that this function will only be called once per + translation unit. */ static void -do_dtors (start) - tree start; +start_static_storage_duration_function () { - tree vars; - int initp; + tree parm_types; + tree type; + + /* Create the parameters. */ + parm_types = void_list_node; + parm_types = perm_tree_cons (NULL_TREE, integer_type_node, parm_types); + parm_types = perm_tree_cons (NULL_TREE, integer_type_node, parm_types); + type = build_function_type (void_type_node, parm_types); + + /* Create the FUNCTION_DECL itself. */ + ssdf_decl = build_lang_decl (FUNCTION_DECL, + get_identifier (SSDF_IDENTIFIER), + type); + TREE_PUBLIC (ssdf_decl) = 0; + DECL_ARTIFICIAL (ssdf_decl) = 1; + DECL_INLINE (ssdf_decl) = 1; + + /* Create the argument list. */ + initialize_p_decl = build_decl (PARM_DECL, + get_identifier (INITIALIZE_P_IDENTIFIER), + integer_type_node); + DECL_CONTEXT (initialize_p_decl) = ssdf_decl; + DECL_ARG_TYPE (initialize_p_decl) = integer_type_node; + TREE_USED (initialize_p_decl) = 1; + priority_decl = build_decl (PARM_DECL, get_identifier (PRIORITY_IDENTIFIER), + integer_type_node); + DECL_CONTEXT (priority_decl) = ssdf_decl; + DECL_ARG_TYPE (priority_decl) = integer_type_node; + TREE_USED (priority_decl) = 1; + + TREE_CHAIN (initialize_p_decl) = priority_decl; + DECL_ARGUMENTS (ssdf_decl) = initialize_p_decl; + + /* Start the function itself. This is equivalent to declarating the + function as: + + static inline void __ssdf (int __initialize_p, init __priority_p); + + It is static because we only need to call this function from the + various constructor and destructor functions for this module. */ + start_function (/*specs=*/NULL_TREE, + ssdf_decl, + /*attrs=*/NULL_TREE, + /*pre_parsed_p=*/1); + + /* Set up the scope of the outermost block in the function. */ + store_parm_decls (); + pushlevel (0); + clear_last_expr (); + push_momentary (); + expand_start_bindings (0); - initp = TREE_INT_CST_LOW (TREE_PURPOSE (start)); - vars = TREE_VALUE (start); + /* Initialize the map from priority numbers to information about + that priority level. */ + priority_info_map = splay_tree_new (splay_tree_compare_ints, + /*delete_key_fn=*/0, + /*delete_value_fn=*/ + (splay_tree_delete_value_fn) &free); +} - for (; vars && vars != error_mark_node; vars = TREE_CHAIN (vars)) +/* Generate the initialization code for the priority indicated in N. */ + +static int +generate_inits_for_priority (n, data) + splay_tree_node n; + void *data ATTRIBUTE_UNUSED; +{ + int priority = (int) n->key; + priority_info pi = (priority_info) n->value; + + /* For each priority N which has been used generate code which looks + like: + + if (__priority == N) { + if (__initialize_p) + ... + else + ... + } + + We use the sequences we've accumulated to fill in the `...'s. */ + expand_start_cond (build_binary_op (EQ_EXPR, + priority_decl, + build_int_2 (priority, 0)), + /*exit_flag=*/0); + + /* Do the initializations. */ + expand_start_cond (build_binary_op (NE_EXPR, + initialize_p_decl, + integer_zero_node), + /*exit_flag=*/0); + if (pi->initialization_sequence) { - tree decl = TREE_VALUE (vars); - tree type = TREE_TYPE (decl); - tree temp; + rtx insns; - if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars) - && ! DECL_EXTERNAL (decl)) - { - int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl) - || DECL_ONE_ONLY (decl) - || DECL_WEAK (decl))); - - if (! current_function_decl) - start_objects ('D', initp); - - /* Set these global variables so that GDB at least puts - us near the declaration which required the initialization. */ - input_filename = DECL_SOURCE_FILE (decl); - lineno = DECL_SOURCE_LINE (decl); - emit_note (input_filename, lineno); - - /* Because of: + push_to_sequence (pi->initialization_sequence); + insns = gen_sequence (); + end_sequence (); + + emit_insn (insns); + } - [class.access.spec] + /* Do the destructions. */ + expand_start_else (); + if (pi->destruction_sequence) + { + rtx insns; - Access control for implicit calls to the constructors, - the conversion functions, or the destructor called to - create and destroy a static data member is performed as - if these calls appeared in the scope of the member's - class. + push_to_sequence (pi->destruction_sequence); + insns = gen_sequence (); + end_sequence (); - we must convince enforce_access to let us access the - DECL. */ - if (member_p (decl)) - { - DECL_CLASS_CONTEXT (current_function_decl) - = DECL_CONTEXT (decl); - DECL_STATIC_FUNCTION_P (current_function_decl) = 1; - } + emit_insn (insns); + } + + /* Close out the conditionals. */ + expand_end_cond (); + expand_end_cond (); - temp = build_cleanup (decl); + /* Don't stop iterating. */ + return 0; +} - if (protect) - { - tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl)); - sentry = build_unary_op (PREDECREMENT_EXPR, sentry, 0); - sentry = build_binary_op (EQ_EXPR, sentry, integer_zero_node); - expand_start_cond (sentry, 0); - } +/* Finish the generation of the function which performs initialization + and destruction of objects with static storage duration. After + this point, no more such objects can be created. */ - expand_expr_stmt (temp); +static void +finish_static_storage_duration_function () +{ + splay_tree_foreach (priority_info_map, + generate_inits_for_priority, + /*data=*/0); - if (protect) - expand_end_cond (); - - /* Now that we're done with DECL we don't need to pretend to - be a member of its class any longer. */ - DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE; - DECL_STATIC_FUNCTION_P (current_function_decl) = 0; - } + /* Close out the function. */ + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 0, 0); + pop_momentary (); + finish_function (lineno, 0, 0); +} + +/* Return the information about the indicated PRIORITY level. If no + code to handle this level has yet been generated, generate the + appropriate prologue. */ + +static priority_info +get_priority_info (priority) + int priority; +{ + priority_info pi; + splay_tree_node n; + + n = splay_tree_lookup (priority_info_map, + (splay_tree_key) priority); + if (!n) + { + /* Create a new priority information structure, and insert it + into the map. */ + pi = (priority_info) xmalloc (sizeof (struct priority_info_s)); + pi->initialization_sequence = NULL_RTX; + pi->destruction_sequence = NULL_RTX; + splay_tree_insert (priority_info_map, + (splay_tree_key) priority, + (splay_tree_value) pi); } + else + pi = (priority_info) n->value; - finish_objects ('D', initp); + return pi; } -/* Generate a function to run a set of global constructors. START is - either NULL_TREE or a node indicating a set of constructors with the - same init priority. Subroutine of finish_file. */ +/* Generate code to do the static initialization of DECL. The + initialization is INIT. If DECL may be initialized more than once + in different object files, SENTRY is the guard variable to + check. PRIORITY is the priority for the initialization. */ static void -do_ctors (start) - tree start; +do_static_initialization (decl, init, sentry, priority) + tree decl; + tree init; + tree sentry; + int priority; { - tree vars; - int initp; + priority_info pi; - initp = TREE_INT_CST_LOW (TREE_PURPOSE (start)); - vars = TREE_VALUE (start); + /* Get the priority information for this PRIORITY, */ + pi = get_priority_info (priority); + if (!pi->initialization_sequence) + start_sequence (); + else + push_to_sequence (pi->initialization_sequence); + + /* Tell the debugger that we are at the location of the static + variable in question. */ + emit_note (input_filename, lineno); + + /* If there's a SENTRY, we only do the initialization if it is + zero, i.e., if we are the first to initialize it. */ + if (sentry) + expand_start_cond (build_binary_op (EQ_EXPR, + build_unary_op (PREINCREMENT_EXPR, + sentry, + /*noconvert=*/0), + integer_one_node), + /*exit_flag=*/0); + + /* Prepare a binding level for temporaries created during the + initialization. */ + expand_start_target_temps (); + + if (IS_AGGR_TYPE (TREE_TYPE (decl)) + || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + expand_aggr_init (decl, init, 0); + else 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, EXPAND_NORMAL); + else + expand_assignment (decl, init, 0, 0); + + /* The expression might have involved increments and decrements. */ + emit_queue (); - /* Reverse the list so it's in the right order for ctors. */ - vars = nreverse (vars); + /* Cleanup any temporaries needed for the initial value. */ + expand_end_target_temps (); - for (; vars && vars != error_mark_node; vars = TREE_CHAIN (vars)) - { - tree decl = TREE_VALUE (vars); - tree init = TREE_PURPOSE (vars); - - /* If this was a static attribute within some function's scope, - then don't initialize it here. Also, don't bother - with initializers that contain errors. */ - if (TREE_STATIC (vars) - || DECL_EXTERNAL (decl) - || (init && TREE_CODE (init) == TREE_LIST - && value_member (error_mark_node, init))) - continue; + /* Close the conditional opened above. */ + if (sentry) + expand_end_cond (); - if (TREE_CODE (decl) == VAR_DECL) - { - int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl) - || DECL_ONE_ONLY (decl) - || DECL_WEAK (decl))); - - if (! current_function_decl) - start_objects ('I', initp); - - /* Set these global variables so that GDB at least puts - us near the declaration which required the initialization. */ - input_filename = DECL_SOURCE_FILE (decl); - lineno = DECL_SOURCE_LINE (decl); - emit_note (input_filename, lineno); - - /* 9.5p5: The initializer of a static member of a class has - the same access rights as a member function. */ - if (member_p (decl)) - { - DECL_CLASS_CONTEXT (current_function_decl) - = DECL_CONTEXT (decl); - DECL_STATIC_FUNCTION_P (current_function_decl) = 1; - } + /* Save the sequence for later use. */ + pi->initialization_sequence = get_insns (); + end_sequence (); +} - if (protect) - { - tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl)); - sentry = build_unary_op (PREINCREMENT_EXPR, sentry, 0); - sentry = build_binary_op - (EQ_EXPR, sentry, integer_one_node); - expand_start_cond (sentry, 0); - } +/* Generate code to do the static destruction of DECL. If DECL may be + initialized more than once in different object files, SENTRY is the + guard variable to check. PRIORITY is the priority for the + destruction. */ - expand_start_target_temps (); +static void +do_static_destruction (decl, sentry, priority) + tree decl; + tree sentry; + int priority; +{ + rtx new_insns; + priority_info pi; - if (IS_AGGR_TYPE (TREE_TYPE (decl)) - || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - expand_aggr_init (decl, init, 0); - else 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, EXPAND_NORMAL); - } - else - expand_assignment (decl, init, 0, 0); - - /* The expression might have involved increments and - decrements. */ - emit_queue (); + /* FIXME: We need destructions to be run in reverse order! */ - /* Cleanup any temporaries needed for the initial value. */ - expand_end_target_temps (); + /* If we don't need a destructor, there's nothing to do. */ + if (!TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl))) + return; + + /* Get the priority information for this PRIORITY, */ + pi = get_priority_info (priority); + if (!pi->destruction_sequence) + start_sequence (); + else + push_to_sequence (pi->destruction_sequence); - if (protect) - expand_end_cond (); + /* Start a new sequence to handle just this destruction. */ + start_sequence (); - DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE; - DECL_STATIC_FUNCTION_P (current_function_decl) = 0; - } - else if (decl == error_mark_node) - /* OK */; - else - my_friendly_abort (22); - } + /* Tell the debugger that we are at the location of the static + variable in question. */ + emit_note (input_filename, lineno); + + /* If there's a SENTRY, we only do the initialization if it is + one, i.e., if we are the last to initialize it. */ + if (sentry) + expand_start_cond (build_binary_op (EQ_EXPR, + build_unary_op (PREDECREMENT_EXPR, + sentry, + /*nonconvert=*/1), + integer_one_node), + /*exit_flag=*/0); + + /* Actually to the destruction. */ + expand_expr_stmt (build_cleanup (decl)); + + /* Close the conditional opened above. */ + if (sentry) + expand_end_cond (); + + /* Insert the NEW_INSNS before the current insns. (Destructions are + run in reverse order of initializations.) */ + new_insns = gen_sequence (); + end_sequence (); + if (pi->destruction_sequence) + emit_insn_before (new_insns, pi->destruction_sequence); + else + emit_insn (new_insns); - finish_objects ('I', initp); + /* Save the sequence for later use. */ + pi->destruction_sequence = get_insns (); + end_sequence (); } -/* This routine is called from the last rule in yyparse (). - Its job is to create all the code needed to initialize and - destroy the global aggregates. We do the destruction - first, since that way we only need to reverse the decls once. */ +/* Add code to the static storage duration function that will handle + DECL (a static variable that needs initializing and/or destruction) + with the indicated PRIORITY. If DECL needs initializing, INIT is + the initializer. */ -void -finish_file () +static void +do_static_initialization_and_destruction (decl, init) + tree decl; + tree init; { - extern int lineno; - int start_time, this_time; + tree sentry = NULL_TREE; + int priority; - tree fnname; - tree vars; - int needs_cleaning = 0, needs_messing_up = 0; + /* Deal gracefully with error. */ + if (decl == error_mark_node) + return; - at_eof = 1; + /* The only things that can be initialized are variables. */ + my_friendly_assert (TREE_CODE (decl) == VAR_DECL, 19990420); - /* Bad parse errors. Just forget about it. */ - if (! global_bindings_p () || current_class_type || decl_namespace_list) + /* If this object is not defined, we don't need to do anything + here. */ + if (DECL_EXTERNAL (decl)) return; - start_time = get_run_time (); - - /* Otherwise, GDB can get confused, because in only knows - about source for LINENO-1 lines. */ - lineno -= 1; + /* Also, if the initializer already contains errors, we can bail out + now. */ + if (init && TREE_CODE (init) == TREE_LIST + && value_member (error_mark_node, init)) + return; - interface_unknown = 1; - interface_only = 0; + /* Trick the compiler into thinking we are at the file and line + where DECL was declared so that error-messages make sense, and so + that the debugger will show somewhat sensible file and line + information. */ + input_filename = DECL_SOURCE_FILE (decl); + lineno = DECL_SOURCE_LINE (decl); - for (fnname = pending_templates; fnname; fnname = TREE_CHAIN (fnname)) - { - tree srcloc = TREE_PURPOSE (fnname); - tree decl = TREE_VALUE (fnname); + /* Because of: - input_filename = SRCLOC_FILE (srcloc); - lineno = SRCLOC_LINE (srcloc); + [class.access.spec] - if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't') - { - instantiate_class_template (decl); - if (CLASSTYPE_TEMPLATE_INSTANTIATION (decl)) - for (vars = TYPE_METHODS (decl); vars; vars = TREE_CHAIN (vars)) - if (! DECL_ARTIFICIAL (vars)) - instantiate_decl (vars); - } - else - instantiate_decl (decl); - } + Access control for implicit calls to the constructors, + the conversion functions, or the destructor called to + create and destroy a static data member is performed as + if these calls appeared in the scope of the member's + class. - for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname)) + we pretend we are in a static member function of the class of + which the DECL is a member. */ + if (member_p (decl)) { - tree args, fn, decl = TREE_VALUE (fnname); - - if (DECL_INITIAL (decl)) - continue; - - fn = TREE_PURPOSE (fnname); - args = get_bindings (fn, decl, NULL_TREE); - fn = instantiate_template (fn, args); - instantiate_decl (fn); + DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl); + DECL_STATIC_FUNCTION_P (current_function_decl) = 1; } + + /* We need a sentry if this is an object with external linkage that + might be initialized in more than one place. */ + if (TREE_PUBLIC (decl) && (DECL_COMMON (decl) + || DECL_ONE_ONLY (decl) + || DECL_WEAK (decl))) + sentry = get_sentry (DECL_ASSEMBLER_NAME (decl)); + + /* Generate the code to actually do the intialization and + destruction. */ + priority = DECL_INIT_PRIORITY (decl); + if (!priority) + priority = DEFAULT_INIT_PRIORITY; + do_static_initialization (decl, init, sentry, priority); + do_static_destruction (decl, sentry, priority); + + /* Now that we're done with DECL we don't need to pretend to be a + member of its class any longer. */ + DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE; + DECL_STATIC_FUNCTION_P (current_function_decl) = 0; +} - cat_namespace_levels(); +/* Generate a static constructor (if CONSTRUCTOR_P) or destructor + (otherwise) that will initialize all gobal objects with static + storage duration having the indicated PRIORITY. */ - /* Push into C language context, because that's all - we'll need here. */ - push_lang_context (lang_name_c); +static void +generate_ctor_or_dtor_function (constructor_p, priority) + int constructor_p; + int priority; +{ + char function_key; + tree arguments; -#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 + /* We use `I' to indicate initialization and `D' to indicate + destruction. */ + if (constructor_p) + function_key = 'I'; + else + function_key = 'D'; + + /* Begin the function. */ + start_objects (function_key, priority); + + /* Call the static storage duration function with appropriate + arguments. */ + arguments = tree_cons (NULL_TREE, build_int_2 (priority, 0), + NULL_TREE); + arguments = tree_cons (NULL_TREE, build_int_2 (constructor_p, 0), + arguments); + expand_expr_stmt (build_function_call (ssdf_decl, arguments)); + + /* If we're generating code for the DEFAULT_INIT_PRIORITY, throw in + calls to any functions marked with attributes indicating that + they should be called at initialization- or destruction-time. */ + if (priority == DEFAULT_INIT_PRIORITY) + { + tree fns; + + for (fns = constructor_p ? static_ctors : static_dtors; + fns; + fns = TREE_CHAIN (fns)) + expand_expr_stmt (build_function_call (TREE_VALUE (fns), NULL_TREE)); + } - for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars)) - if (! TREE_ASM_WRITTEN (TREE_VALUE (vars))) - rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1); - vars = static_aggregates; + /* Close out the function. */ + finish_objects (function_key, priority); +} - if (static_ctors || vars) - needs_messing_up = 1; - if (static_dtors || vars) - needs_cleaning = 1; +/* Generate constructor and destructor functions for the priority + indicated by N. DATA is really an `int*', and it set to `1' if we + process the DEFAULT_INIT_PRIORITY. */ - setup_initp (); +static int +generate_ctor_and_dtor_functions_for_priority (n, data) + splay_tree_node n; + void *data; +{ + int priority = (int) n->key; + priority_info pi = (priority_info) n->value; + int *did_default_priority_p = (int*) data; + + if (priority == DEFAULT_INIT_PRIORITY) + *did_default_priority_p = 1; + + /* Generate the functions themselves, but only if they are really + needed. */ + if (pi->initialization_sequence + || (priority == DEFAULT_INIT_PRIORITY && static_ctors)) + generate_ctor_or_dtor_function (/*constructor_p=*/1, + priority); + if (pi->destruction_sequence + || (priority == DEFAULT_INIT_PRIORITY && static_dtors)) + generate_ctor_or_dtor_function (/*constructor_p=*/0, + priority); + + /* Keep iterating. */ + return 0; +} - /* After setup_initp, the aggregates are listed in reverse declaration - order, for cleaning. */ - if (needs_cleaning) - for (vars = static_aggregates_initp; vars; vars = TREE_CHAIN (vars)) - do_dtors (vars); +/* This routine is called from the last rule in yyparse (). + Its job is to create all the code needed to initialize and + destroy the global aggregates. We do the destruction + first, since that way we only need to reverse the decls once. */ - /* do_ctors will reverse the lists for messing up. */ - if (needs_messing_up) - for (vars = static_aggregates_initp; vars; vars = TREE_CHAIN (vars)) - do_ctors (vars); +void +finish_file () +{ + extern int lineno; + int start_time, this_time; + int did_default_priority_p = 0; + tree vars; + int reconsider; + size_t i; - permanent_allocation (1); + at_eof = 1; - /* Done with C language context needs. */ - pop_lang_context (); + /* Bad parse errors. Just forget about it. */ + if (! global_bindings_p () || current_class_type || decl_namespace_list) + return; - /* Let expand_static_init know it's too late for more ctors. */ - at_eof = 2; + start_time = get_run_time (); - /* Now write out any static class variables (which may have since - learned how to be initialized). */ - for (; pending_statics; pending_statics = TREE_CHAIN (pending_statics)) - { - tree decl = TREE_VALUE (pending_statics); + /* Otherwise, GDB can get confused, because in only knows + about source for LINENO-1 lines. */ + lineno -= 1; - if (TREE_ASM_WRITTEN (decl)) - continue; + interface_unknown = 1; + interface_only = 0; - /* Output DWARF debug information. */ -#ifdef DWARF_DEBUGGING_INFO - if (write_symbols == DWARF_DEBUG) - dwarfout_file_scope_decl (decl, 1); -#endif -#ifdef DWARF2_DEBUGGING_INFO - if (write_symbols == DWARF2_DEBUG) - dwarf2out_decl (decl); -#endif + /* We now have to write out all the stuff we put off writing out. + These include: - /* We currently handle template statics here. We ought to handle - them the same way we do template functions, i.e. only emit them if - the symbol is needed. */ - import_export_decl (decl); - if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (decl)) - DECL_EXTERNAL (decl) = 0; + o Template specializations that we have not yet instantiated, + but which are needed. + o Initialization and destruction for non-local objects with + static storage duration. (Local objects with static storage + duration are initialized when their scope is first entered, + and are cleaned up via atexit.) + o Virtual function tables. - rest_of_decl_compilation - (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 1, 1); - } + All of these may cause others to be needed. For example, + instantiating one function may cause another to be needed, and + generating the intiailzer for an object may cause templates to be + instantiated, etc., etc. */ this_time = get_run_time (); parse_time -= this_time - start_time; varconst_time += this_time - start_time; - start_time = get_run_time (); + permanent_allocation (1); - if (flag_handle_signatures) - walk_sigtables ((void (*) PROTO ((tree, tree))) 0, - finish_sigtable_vardecl); + /* Create the function that will contain all initializations and + destructions for objects with static storage duration. We cannot + conclude that because a symbol is not TREE_SYMBOL_REFERENCED the + corresponding entity is not used until we call finish_function + for the static storage duration function. We give C linkage to + static constructors and destructors. */ + push_lang_context (lang_name_c); + start_static_storage_duration_function (); + push_to_top_level (); - for (fnname = saved_inlines; fnname; fnname = TREE_CHAIN (fnname)) + do { - tree decl = TREE_VALUE (fnname); - import_export_decl (decl); + reconsider = 0; + + /* If there are templates that we've put off instantiating, do + them now. */ + instantiate_pending_templates (); + + /* Write out signature-tables and virtual tables as required. + Note that writing out the virtual table for a template class + may cause the instantiation of members of that class. */ + if (flag_handle_signatures + && walk_globals (sigtable_decl_p, + finish_sigtable_vardecl, + /*data=*/0)) + reconsider = 1; + if (walk_globals (vtable_decl_p, + finish_vtable_vardecl, + /*data=*/0)) + reconsider = 1; + + /* Come back to the static storage duration function; we're + about to emit instructions there for static initializations + and such. */ + pop_from_top_level (); + /* The list of objects with static storage duration is built up + in reverse order, so we reverse it here. We also clear + STATIC_AGGREGATES so that any new aggregates added during the + initialization of these will be initialized in the correct + order when we next come around the loop. */ + vars = nreverse (static_aggregates); + static_aggregates = NULL_TREE; + while (vars) + { + if (! TREE_ASM_WRITTEN (TREE_VALUE (vars))) + rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1); + do_static_initialization_and_destruction (TREE_VALUE (vars), + TREE_PURPOSE (vars)); + reconsider = 1; + vars = TREE_CHAIN (vars); + } + push_to_top_level (); + + /* Go through the various inline functions, and see if any need + synthesizing. */ + for (i = 0; i < saved_inlines_used; ++i) + { + tree decl = VARRAY_TREE (saved_inlines, i); + import_export_decl (decl); + if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) + && TREE_USED (decl) + && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl))) + { + /* Even though we're already at the top-level, we push + there again. That way, when we pop back a few lines + hence, all of our state is restored. Otherwise, + finish_function doesn't clean things up, and we end + up with CURRENT_FUNCTION_DECL set. */ + push_to_top_level (); + if (DECL_TINFO_FN_P (decl)) + synthesize_tinfo_fn (decl); + else + synthesize_method (decl); + pop_from_top_level (); + reconsider = 1; + } + } + } + while (reconsider); + + /* Finish up the static storage duration function, now that we now + there can be no more things in need of initialization or + destruction. */ + pop_from_top_level (); + finish_static_storage_duration_function (); + + /* Generate initialization and destruction functions for all + priorities for which they are required. */ + if (priority_info_map) + splay_tree_foreach (priority_info_map, + generate_ctor_and_dtor_functions_for_priority, + &did_default_priority_p); + + if (!did_default_priority_p) + { + /* Even if there were no explicit initializations or + destructions required, we may still have to handle the + default priority if there functions declared as constructors + or destructors via attributes. */ + if (static_ctors) + generate_ctor_or_dtor_function (/*constructor_p=*/1, + DEFAULT_INIT_PRIORITY); + if (static_dtors) + generate_ctor_or_dtor_function (/*constructor_p=*/0, + DEFAULT_INIT_PRIORITY); } - mark_all_runtime_matches (); - - /* 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 = 1; /* More may be referenced; check again */ - - while (reconsider) - { - tree *p = &saved_inlines; - reconsider = 0; - - /* We need to do this each time so that newly completed template - types don't wind up at the front of the list. Sigh. */ - vars = build_decl (TYPE_DECL, make_anon_name (), integer_type_node); - DECL_IGNORED_P (vars) = 1; - SET_DECL_ARTIFICIAL (vars); - pushdecl (vars); - - reconsider |= walk_vtables ((void (*) PROTO((tree, tree))) 0, - finish_vtable_vardecl); - - while (*p) - { - tree decl = TREE_VALUE (*p); - - if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl) - && TREE_USED (decl) - && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl))) - { - if (DECL_MUTABLE_P (decl)) - synthesize_tinfo_fn (decl); - else - synthesize_method (decl); - reconsider = 1; - } - - /* Catch new template instantiations. */ - if (decl != TREE_VALUE (*p)) - continue; - - if (TREE_ASM_WRITTEN (decl) - || (DECL_SAVED_INSNS (decl) == 0 - && ! DECL_ARTIFICIAL (decl))) - *p = TREE_CHAIN (*p); - else if (DECL_INITIAL (decl) == 0) - p = &TREE_CHAIN (*p); - else if ((TREE_PUBLIC (decl) && ! DECL_COMDAT (decl)) - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) - || flag_keep_inline_functions) - { - if (DECL_NOT_REALLY_EXTERN (decl)) - { - DECL_EXTERNAL (decl) = 0; - reconsider = 1; - /* We can't inline this function after it's been - emitted. We want a variant of - output_inline_function that doesn't prevent - subsequent integration... */ - DECL_INLINE (decl) = 0; - output_inline_function (decl); - permanent_allocation (1); - } - - *p = TREE_CHAIN (*p); - } - else - p = &TREE_CHAIN (*p); - } - } - - /* It's possible that some of the remaining inlines will still be - needed. For example, a static inline whose address is used in - the initializer for a file-scope static variable will be - needed. Code in compile_file will handle this, but we mustn't - pretend that there are no definitions for the inlines, or it - won't be able to. + /* We're done with the splay-tree now. */ + if (priority_info_map) + splay_tree_delete (priority_info_map); - FIXME: This won't catch member functions. We should really - unify this stuff with the compile_file stuff. */ - for (vars = saved_inlines; vars != NULL_TREE; vars = TREE_CHAIN (vars)) - { - tree decl = TREE_VALUE (vars); + /* We're done with static constructors, so we can go back to "C++" + linkage now. */ + pop_lang_context (); - if (DECL_NOT_REALLY_EXTERN (decl) - && !DECL_COMDAT (decl) - && DECL_INITIAL (decl) != NULL_TREE) - DECL_EXTERNAL (decl) = 0; - } - } + /* Mark all functions that might deal with exception-handling as + referenced. */ + mark_all_runtime_matches (); /* Now delete from the chain of variables all virtual function tables. We output them all ourselves, because each will be treated specially. */ + walk_globals (vtable_decl_p, prune_vtable_vardecl, /*data=*/0); + + /* We'll let wrapup_global_declarations handle the inline functions, + but it will be fooled by DECL_NOT_REALL_EXTERN funtions, so we + fix them up here. */ + for (i = 0; i < saved_inlines_used; ++i) + { + tree decl = VARRAY_TREE (saved_inlines, i); + + if (DECL_NOT_REALLY_EXTERN (decl)) + DECL_EXTERNAL (decl) = 0; + } + + /* We haven't handled non-local objects that don't need dynamic + initialization. Do that now. */ + do + { + if (saved_inlines) + reconsider + |= wrapup_global_declarations (&VARRAY_TREE (saved_inlines, 0), + saved_inlines_used); + reconsider + = walk_namespaces (wrapup_globals_for_namespace, /*data=*/0); + + /* Static data members are just like namespace-scope globals. */ + for (i = 0; i < pending_statics_used; ++i) + { + tree decl = VARRAY_TREE (pending_statics, i); + if (TREE_ASM_WRITTEN (decl)) + continue; + import_export_decl (decl); + if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (decl)) + DECL_EXTERNAL (decl) = 0; + } + if (pending_statics) + reconsider + |= wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0), + pending_statics_used); + } + while (reconsider); - walk_vtables ((void (*) PROTO((tree, tree))) 0, - prune_vtable_vardecl); + /* Now, issue warnings about static, but not defined, functions, + etc. */ + walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider); finish_repo (); diff --git a/gcc/cp/error.c b/gcc/cp/error.c index b59b61922cb..f0e59bcc4a5 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -86,6 +86,11 @@ static char *scratch_firstobj; OB_PUTCP (digit_buffer); } while (0) # define OB_UNPUT(N) obstack_blank (&scratch_obstack, - (N)); +# define OB_END_TEMPLATE_ID() \ + ((obstack_next_free (&scratch_obstack) != obstack_base (&scratch_obstack) \ + && obstack_next_free (&scratch_obstack)[-1] == '>') \ + ? OB_PUTC2 (' ', '>') : OB_PUTC ('>')) + # define NEXT_CODE(t) (TREE_CODE (TREE_TYPE (t))) enum pad { none, before, after }; @@ -292,7 +297,7 @@ dump_type_real (t, v, canonical_name) if (i < TREE_VEC_LENGTH (args)-1) OB_PUTC2 (',', ' '); } - OB_PUTC ('>'); + OB_END_TEMPLATE_ID (); } break; @@ -863,7 +868,8 @@ dump_decl (t, v) } if (len != 0) OB_UNPUT (2); - OB_PUTC2 ('>', ' '); + OB_END_TEMPLATE_ID (); + OB_PUTC (' '); } nreverse(orig_args); @@ -905,7 +911,7 @@ dump_decl (t, v) if (TREE_CHAIN (args)) OB_PUTC2 (',', ' '); } - OB_PUTC ('>'); + OB_END_TEMPLATE_ID (); } break; @@ -1199,7 +1205,7 @@ dump_function_name (t) } } } - OB_PUTC ('>'); + OB_END_TEMPLATE_ID (); } } diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index a9bb9cf4030..db8fdd50db2 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -65,9 +65,9 @@ static int interface_strcmp PROTO((const char *)); static int readescape PROTO((int *)); static char *extend_token_buffer PROTO((const char *)); static void consume_string PROTO((struct obstack *, int)); -static void set_typedecl_interface_info PROTO((tree, tree)); +static int set_typedecl_interface_info PROTO((tree *, void *)); static void feed_defarg PROTO((tree, tree)); -static int set_vardecl_interface_info PROTO((tree, tree)); +static int set_vardecl_interface_info PROTO((tree *, void *)); static void store_pending_inline PROTO((tree, struct pending_inline *)); static void reinit_parse_for_expr PROTO((struct obstack *)); static int *init_cpp_parse PROTO((void)); @@ -1134,32 +1134,35 @@ interface_strcmp (s) return 1; } -static void -set_typedecl_interface_info (prev, vars) - tree prev ATTRIBUTE_UNUSED, vars; +static int +set_typedecl_interface_info (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; { - tree id = get_time_identifier (DECL_SOURCE_FILE (vars)); + tree id = get_time_identifier (DECL_SOURCE_FILE (*t)); tree fileinfo = TIME_IDENTIFIER_FILEINFO (id); - tree type = TREE_TYPE (vars); + tree type = TREE_TYPE (*t); CLASSTYPE_INTERFACE_ONLY (type) = TREE_INT_CST_LOW (fileinfo) - = interface_strcmp (file_name_nondirectory (DECL_SOURCE_FILE (vars))); + = interface_strcmp (file_name_nondirectory (DECL_SOURCE_FILE (*t))); + return 0; } static int -set_vardecl_interface_info (prev, vars) - tree prev, vars; +set_vardecl_interface_info (t, data) + tree *t; + void *data ATTRIBUTE_UNUSED; { - tree type = DECL_CONTEXT (vars); + tree type = DECL_CONTEXT (*t); if (CLASSTYPE_INTERFACE_KNOWN (type)) { if (CLASSTYPE_INTERFACE_ONLY (type)) - set_typedecl_interface_info (prev, TYPE_MAIN_DECL (type)); + set_typedecl_interface_info (&TYPE_MAIN_DECL (type), data); else CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 1; - DECL_EXTERNAL (vars) = CLASSTYPE_INTERFACE_ONLY (type); - TREE_PUBLIC (vars) = 1; + DECL_EXTERNAL (*t) = CLASSTYPE_INTERFACE_ONLY (type); + TREE_PUBLIC (*t) = 1; return 1; } return 0; @@ -2461,7 +2464,14 @@ linenum: main_input_filename = input_filename; if (write_virtuals == 3) - walk_vtables (set_typedecl_interface_info, set_vardecl_interface_info); + { + walk_globals (vtable_decl_p, + set_vardecl_interface_info, + /*data=*/0); + walk_globals (vtype_decl_p, + set_typedecl_interface_info, + /*data=*/0); + } } extract_interface_info (); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index aeb827f3e9c..12c8a95e2e7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -50,15 +50,21 @@ extern struct obstack permanent_obstack; extern int lineno; extern char *input_filename; -struct pending_inline *pending_template_expansions; tree current_template_parms; HOST_WIDE_INT processing_template_decl; -tree pending_templates; +/* The PENDING_TEMPLATES is a TREE_LIST of templates whose + instantiations have been deferred, either because their definitions + were not yet available, or because we were putting off doing the + work. The TREE_PURPOSE of each entry is a SRCLOC indicating where + the instantiate request occurred; the TREE_VALUE is a either a DECL + (for a function or static data member), or a TYPE (for a class) + indicating what we are hoping to instantiate. */ +static tree pending_templates; static tree *template_tail = &pending_templates; -tree maybe_templates; +static tree maybe_templates; static tree *maybe_template_tail = &maybe_templates; int minimal_parse_mode; @@ -5124,7 +5130,7 @@ instantiate_class_template (type) input_filename = DECL_SOURCE_FILE (typedecl); unreverse_member_declarations (type); - type = finish_struct_1 (type, 0); + finish_struct_1 (type, 0); CLASSTYPE_GOT_SEMICOLON (type) = 1; /* Clear this now so repo_template_used is happy. */ @@ -9421,6 +9427,115 @@ out: return d; } +/* Run through the list of templates that we wish we could + instantiate, and instantiate any we can. */ + +int +instantiate_pending_templates () +{ + tree *t; + int instantiated_something = 0; + int reconsider; + + do + { + reconsider = 0; + + t = &pending_templates; + while (*t) + { + tree srcloc = TREE_PURPOSE (*t); + tree instantiation = TREE_VALUE (*t); + + input_filename = SRCLOC_FILE (srcloc); + lineno = SRCLOC_LINE (srcloc); + + if (TREE_CODE_CLASS (TREE_CODE (instantiation)) == 't') + { + tree fn; + + if (!TYPE_SIZE (instantiation)) + { + instantiate_class_template (instantiation); + if (CLASSTYPE_TEMPLATE_INSTANTIATION (instantiation)) + for (fn = TYPE_METHODS (instantiation); + fn; + fn = TREE_CHAIN (fn)) + if (! DECL_ARTIFICIAL (fn)) + instantiate_decl (fn); + if (TYPE_SIZE (instantiation)) + { + instantiated_something = 1; + reconsider = 1; + } + } + + if (TYPE_SIZE (instantiation)) + /* If INSTANTIATION has been instantiated, then we don't + need to consider it again in the future. */ + *t = TREE_CHAIN (*t); + else + t = &TREE_CHAIN (*t); + } + else + { + if (DECL_TEMPLATE_INSTANTIATION (instantiation) + && !DECL_TEMPLATE_INSTANTIATED (instantiation)) + { + instantiation = instantiate_decl (instantiation); + if (DECL_TEMPLATE_INSTANTIATED (instantiation)) + { + instantiated_something = 1; + reconsider = 1; + } + } + + if (!DECL_TEMPLATE_INSTANTIATION (instantiation) + || DECL_TEMPLATE_INSTANTIATED (instantiation)) + /* If INSTANTIATION has been instantiated, then we don't + need to consider it again in the future. */ + *t = TREE_CHAIN (*t); + else + t = &TREE_CHAIN (*t); + } + } + template_tail = t; + + /* Go through the things that are template instantiations if we are + using guiding declarations. */ + t = &maybe_templates; + while (*t) + { + tree template; + tree fn; + tree args; + + fn = TREE_VALUE (*t); + + if (DECL_INITIAL (fn)) + /* If the FN is already defined, then it was either already + instantiated or, even though guiding declarations were + allowed, a non-template definition was provided. */ + ; + else + { + template = TREE_PURPOSE (*t); + args = get_bindings (template, fn, NULL_TREE); + fn = instantiate_template (template, args); + instantiate_decl (fn); + reconsider = 1; + } + + /* Remove this entry from the chain. */ + *t = TREE_CHAIN (*t); + } + maybe_template_tail = t; + } + while (reconsider); + + return instantiated_something; +} + /* Substitute ARGVEC into T, which is a TREE_LIST. In particular, it is an initializer list: the TREE_PURPOSEs are DECLs, and the TREE_VALUEs are initializer values. Used by instantiate_decl. */ diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 15efd618d2e..79fb8006ce8 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -381,7 +381,7 @@ get_tinfo_fn (type) TREE_PUBLIC (d) = 1; DECL_ARTIFICIAL (d) = 1; DECL_NOT_REALLY_EXTERN (d) = 1; - DECL_MUTABLE_P (d) = 1; + SET_DECL_TINFO_FN_P (d); TREE_TYPE (name) = copy_to_permanent (type); pushdecl_top_level (d); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 1d717b2a2bb..6acb50189ea 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2687,12 +2687,6 @@ pod_type_p (t) return 1; } -/* A list of objects which have constructors or destructors - which reside in the global scope. The decl is stored in - the TREE_VALUE slot and the initializer is stored - in the TREE_PURPOSE slot. */ -tree static_aggregates_initp; - /* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid C++-specific attribute for either declaration DECL or type TYPE and 0 otherwise. Plugged into valid_lang_attribute. */ @@ -2773,9 +2767,7 @@ cp_valid_lang_attribute (attr_name, attr_args, decl, type) ("requested init_priority is reserved for internal use"); } - static_aggregates_initp - = perm_tree_cons (initp_expr, decl, static_aggregates_initp); - + DECL_INIT_PRIORITY (decl) = pri; return 1; } diff --git a/gcc/testsuite/g++.old-deja/g++.other/init12.C b/gcc/testsuite/g++.old-deja/g++.other/init12.C new file mode 100644 index 00000000000..ee0a029253a --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/init12.C @@ -0,0 +1,22 @@ +// Build don't run: +// Special g++ Options: -O3 +// Origin: Mark Mitchell <mark@codesourcery.com> + +typedef int (*fp)(); + +struct S +{ + fp f; +}; + +struct T +{ + static int f() {} +}; + +static const S s = { &T::f }; + +int main() +{ + return (*s.f)(); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/link1.C b/gcc/testsuite/g++.old-deja/g++.pt/link1.C new file mode 100644 index 00000000000..b1991f62106 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/link1.C @@ -0,0 +1,29 @@ +// Build don't run: +// Origin: Mark Mitchell <mark@codesourcery.com> + +template <class T> +int f(T); + +template <class T> +struct S { + template <class U> + friend int f(U) { return 0; } +}; + +int k = f(2); + +template <class T> +int g(T); + +int h = g(7); + +template <class T> +int g(T) { + S<T> si; + return 0; +} + +int main() +{ +} + diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static8.C b/gcc/testsuite/g++.old-deja/g++.pt/static8.C new file mode 100644 index 00000000000..172c3c3fe7d --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/static8.C @@ -0,0 +1,32 @@ +// Origin: Mark Mitchell <mark@codesourcery.com> + +int i; + +template <class T> +struct S { + S() { ++i; } + + virtual void g() {} + virtual void f(); + + static S s; +}; + +template <class T> +void S<T>::f() { + s.f(); +} + +S<int> si; + +template <class T> +S<T> S<T>::s; + +int main () +{ + si.g(); + if (i != 2) + return 1; + else + return 0; +} |