]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
cp-tree.h (lang_decl_flags): Remove returns_first_arg and preserves_first_arg.
authorMark Mitchell <mark@codesourcery.com>
Thu, 22 Apr 1999 23:13:12 +0000 (23:13 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 22 Apr 1999 23:13:12 +0000 (23:13 +0000)
* 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.

From-SVN: r26594

15 files changed:
gcc/cp/ChangeLog
gcc/cp/Makefile.in
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl.h
gcc/cp/decl2.c
gcc/cp/error.c
gcc/cp/lex.c
gcc/cp/pt.c
gcc/cp/rtti.c
gcc/cp/tree.c
gcc/testsuite/g++.old-deja/g++.other/init12.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/link1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/static8.C [new file with mode: 0644]

index d8ca82308afdd1994e5ee3a4a3f07c8130409e01..c517e678bf69e8eaa8047f7f456800adb368d0d9 100644 (file)
@@ -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.
index d806506e2c52d05570bf7e0fa3530c15d6356a07..616525c29cf207b78f5c3d2c072e459be41a2175 100644 (file)
@@ -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) \
index 87a82c7beea1a583d282beba8e7a52522b38ac27..9a20b5b093fa7bd6323bb7d5ed85a5195b83bf23 100644 (file)
@@ -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;
 
index b94f6f50af50a3d277cded3549084f7920fbef81..9dccb4d9331b35e90c654525d700f1288110b1ea 100644 (file)
@@ -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;
index 917535a016474b78d748887ab2f36354601b8ac2..5457e9216c31328799b7a301188374805ca8b924 100644 (file)
@@ -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;
+}
+
 \f
 /* 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;
-    }
-}
 \f
 /* 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,
index f55dca55ea753a23bc41b618b01a6591578ca1eb..fcb247e702029d4a1c5c9e29863e0c7cfa38a747 100644 (file)
@@ -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
index ac52f6dd3d65c100f4feea4a3cb8532cae670c4d..ea469f3ef109cd5f04291cf947df68fc5f58c6b9 100644 (file)
@@ -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 ();
 
index b59b61922cbe714b071705b53a8ede17bd3aed0d..f0e59bcc4a5ded7f62b030f564ecb783ae64ce07 100644 (file)
@@ -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 ();
     }
 }
 
index a9bb9cf403066323c8b1b9f1ed8f850d94cfb5f6..db8fdd50db2f815bf07e33a8aac855b7e81e8564 100644 (file)
@@ -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 ();
index aeb827f3e9c45efa20ec98efd95ed764e127ee91..12c8a95e2e741d096efa5b76994b94d990984916 100644 (file)
@@ -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.  */
index 15efd618d2ef79c2b53c0df42055c74de2a3ff03..79fb8006ce885e45303ffd2dceb0cad5e73d8007 100644 (file)
@@ -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);
index 1d717b2a2bbf93bf104f15662b3a23dedacb1f48..6acb50189ea91473aae6c57c935061595e5d663b 100644 (file)
@@ -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 (file)
index 0000000..ee0a029
--- /dev/null
@@ -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 (file)
index 0000000..b1991f6
--- /dev/null
@@ -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 (file)
index 0000000..172c3c3
--- /dev/null
@@ -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;
+}