summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>1999-04-22 23:13:12 +0000
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>1999-04-22 23:13:12 +0000
commitcec1f6a6d37512600d8592206ad4f4cb5e89231a (patch)
treee4a00a2291e86f7c0c50315f152fd043cb14bdad
parenta84da62d098beef3830f994f39662b52b72f167d (diff)
downloadgcc-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/ChangeLog100
-rw-r--r--gcc/cp/Makefile.in3
-rw-r--r--gcc/cp/class.c8
-rw-r--r--gcc/cp/cp-tree.h52
-rw-r--r--gcc/cp/decl.c232
-rw-r--r--gcc/cp/decl.h5
-rw-r--r--gcc/cp/decl2.c1304
-rw-r--r--gcc/cp/error.c14
-rw-r--r--gcc/cp/lex.c40
-rw-r--r--gcc/cp/pt.c123
-rw-r--r--gcc/cp/rtti.c2
-rw-r--r--gcc/cp/tree.c10
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/init12.C22
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/link1.C29
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/static8.C32
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;
+}