PATCH: Support priority argument for constructor/destructor arguments

Mark Mitchell mark@codesourcery.com
Sun Feb 25 07:48:00 GMT 2007


This patch adds support for a priority arguments to constructors and
destructors, so that you can write:

  void f() __attribute__((constructor (500)));
  void g() __attribute__((constructor (600)));

Then, "f" will be run before "g".  This is a backwards-compatible
extension to the constructor attribute, and leverages functionality
already used to support the init_priority attribute in C++.

This patch looks bigger than it is.

* Initialization priorities (for C++ variables) were stored in an
  on-the-side hash table.  I didn't want to create a separate hash
  table for constructor priorities, and yet another for destructor
  priorities.  So, I changed this to be one hash table, mapping
  VAR_DECLs and FUNCTION_DECLs to a pair of priorities { init, fini }.
  (Because priorities are shorts, each node in this table is the same
  size as the nodes in the original table.)  But, that added yet
  another "tree_map", so I refactored tree_map and tree_int_map in the
  obvious object-oriented way, so that we didn't keep duplicating code
  for every tree->T map.  That required touching a few other files.

* The c-common attribute handling was taught about the new optional
  argument to the constructor/destructor attributes.

* The C++ front end was handling constructor/destructor attributes by
  calling the marked functions from within the special routines
  generated for initializing global objects.  That would have required
  reworking to support priorities for the constructor functions, and
  there's no need for the indirection anyhow, so I converted the C++
  front end to use the same direct approach as in C.  (It also allowed
  elimination of the use of TREE_LISTs to store the static_ctors and
  static_dtors lists in C++).

* I added several new test cases.  I also noticed that the C++ tests
  for init_priority had an outdated approach to determining whether
  the target supported the attribute (which requires linker support),
  so I created a new effective target in target-supports.exp.

I tested this on x86_64-unknown-linux-gnu.  However, I couldn't get
Ada to build, so I've grepped for places where the tree_map
refactoring might affect Ada, and fixed the one spot I found.  If
there are more, it will be a simple matter of adding "base.from" in
lieu of "from" for uses of tree_map or tree_int_map.

I plan to go ahead and check this in, with, of course, a pledge to
speedily correct any problems, and, further, explicitly allowing
anyone affected to revert the patch, if they feel necessary, without
consulting with me.  If anyone objects to this plan, please let me
know.

Then, there are a couple of more VxWorks-specific patches which I will
commit as follow-ons.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2007-02-24  Mark Mitchell  <mark@codesourcery.com>

	* doc/extend.texi: Document optional priority argument to
	constructors and destructors.
	* tree.c (init_priority_for_decl): Adjust GTY markers.
	(init_ttree): Use priority-info hash functions for
	init_priority_for_decl.
	(tree_map_eq): Rename to ...
	(tree_map_base_eq): ... this.
	(tree_map_marked_p): Rename to ...
	(tree_map_base_marked_p): ... this.
	(tree_map_base_hash): New function.
	(decl_init_priority_lookup): Rework.
	(decl_fini_priority_lookup): New function.
	(decl_priority_info): New function.
	(decl_init_priority_insert): Use it.
	(decl_fini_priority_insert): Likewise.
	(decl_restrict_base_lookup): Adjust for refactoring of tree_map
	hierarchy.
	(decl_restrict_base_insert): Likewise.
	(decl_debug_expr_insert): Likewise.
	(decl_value_expr_lookup): Likewise.
	(decl_value_expr_insert): Likewise.
	* tree.h (priority_type): New type.
	(decl_init_priority_lookup): Use priority_type.
	(decl_fini_priority_lookup): New function.
	(decl_init_priority_insert): Use priority_type.
	(decl_fini_priority_insert): New function.
	(DECL_HAS_INIT_PRIORITY): Tweak comments.
	(DECL_INIT_PRIORITY): Likewise.
	(SET_DECL_INIT_PRIORITY): Add comment.
	(DECL_FINI_PRIORITY): New macro.
	(SET_DECL_FINI_PRIORITY): Likewise.
	(DEFAULT_INIT_PRIORITY): Document.
	(MAX_INIT_PRIORITY): Likewise.
	(MAX_RESERVED_INIT_PRIORITY): Likewise.
	(tree_map_base): New type.
	(tree_map_base_eq): New function.
	(tree_map_base_hash): Likewise.
	(tree_map_base_marked_p): Likewise.
	(tree_map): Inherit from tree_map_base.
	(tree_map_eq): Make it a macro.
	(tree_map_marked_p): Likewise.
	(tree_int_map): Inherit from tree_map_base.
	(tree_int_map_eq): Make it a macro.
	(tree_int_map_hash): Likewise.
	(tree_int_map_marked_p): Likewise.
	(tree_priority_map): New type.
	(tree_priority_map_eq): New macro.
	(tree_priority_map_hash): Likewise.
	(tree_priority_map_marked_p): Likewise.
	* varasm.c (emults_decl): Adjust for refactoring of tree_map
	hierarchy.
	(emutls_common_1): Likewise.
	* lambda-code.c (replace_uses_equiv_to_x_with_y): Likewise.
	* tree-ssa-structalias.c (heapvar_lookup): Adjust for refactoring
	of tree_map hierarchy.
	* tree-cfg.c (move_stmt_r): Likewise.
	(new_label_mapper): Likewise.
	* c-tree.h (c_expand_body): Move to ...
	* c-common.h (c_expand_body): ... here.
	* c-decl.c (c_expand_body): Move to ...
	* c-common.c (c_expand_body): ... here.
	(c_common_attribute_table): Allow 1 argument for the constructor
	and destructor attributes.
	(get_priority): New function.
	(handle_constructor_attribute): Set DECL_INIT_PRIORITY.
	(handle_destructor_attribute): Set DECL_FINI_PRIORITY.

2007-02-24  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (static_ctors): Remove.
	* cp-tree.h (static_dtors): Likewise.
	* cp-objcp-common.c (decl_shadowed_for_var_lookup): Adjust for
	refactoring of tree_map hierarchy.
	(decl_shadowed_for_var_insert): Likewise.
	* semantics.c (expand_body): Use c_expand_body.
	(expand_or_defer_fn): Don't update static_ctors or static_dtors.
	* decl2.c (static_ctors): Remove.
	(static_dtors): Likewise.
	(generate_ctor_or_dtor_function): Pass NULL_TREE to
	objc_generate_static_init_call.  Do not call static_[cd]tors.
	(generate_ctor_and_dtor_functions_for_priority): Do not check for
	static_[cd]tors.
	(cp_write_global_declarations): Likewise.

2007-02-24  Mark Mitchell  <mark@codesourcery.com>

	* decl.c (annotate_value): Adjust for refactoring of tree_map
	hierarchy.

2007-02-24  Mark Mitchell  <mark@codesourcery.com>

	* gcc.dg/initpri1.c: New test.
	* gcc.dg/initpri2.c: Likewise.
	* g++.dg/special/initpri1.C: New test.
	* g++.dg/special/initpri2.C: Likewise.
	* g++.dg/special/conpr-1.C: Use init_priority effective target.
	* g++.dg/special/conpr-2.C: Likewise.
	* g++.dg/special/conpr-3.C: Likewise.
	* g++.dg/special/conpr-4.C: Likewise.
	* g++.dg/special/initp1.C: Likewise.
	* g++.dg/special/ecos.exp: Remove code to detect availability of
	constructor priorities.
	* lib/target-support.exp (target_init_priority): New function.

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 122239)
+++ doc/extend.texi	(working copy)
@@ -1667,6 +1667,8 @@ specifies that the @samp{const} must be 
 
 @item constructor
 @itemx destructor
+@itemx constructor (@var{priority})
+@itemx destructor (@var{priority})
 @cindex @code{constructor} function attribute
 @cindex @code{destructor} function attribute
 The @code{constructor} attribute causes the function to be called
@@ -1677,6 +1679,16 @@ been called.  Functions with these attri
 initializing data that will be used implicitly during the execution of
 the program.
 
+You may provide an optional integer priority to control the order in
+which constructor and destructor functions are run.  A constructor
+with a smaller priority number runs before a constructor with a larger
+priority number; the opposite relationship holds for destructors.  So,
+if you have a constructor that allocates a resource and a destructor
+that deallocates the same resource, both functions typically have the
+same priority.  The priorities for constructor and destructor
+functions are the same as those specified for namespace-scope C++
+objects (@pxref{C++ Attributes}).
+
 These attributes are not currently implemented for Objective-C@.
 
 @item deprecated
Index: tree.c
===================================================================
--- tree.c	(revision 122239)
+++ tree.c	(working copy)
@@ -146,7 +146,8 @@ static GTY ((if_marked ("tree_map_marked
 static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map))) 
      htab_t value_expr_for_decl;
 
-static GTY ((if_marked ("tree_int_map_marked_p"), param_is (struct tree_int_map)))
+static GTY ((if_marked ("tree_priority_map_marked_p"), 
+	     param_is (struct tree_priority_map)))
   htab_t init_priority_for_decl;
 
 static GTY ((if_marked ("tree_map_marked_p"), param_is (struct tree_map)))
@@ -220,8 +221,8 @@ init_ttree (void)
 
   value_expr_for_decl = htab_create_ggc (512, tree_map_hash,
 					 tree_map_eq, 0);
-  init_priority_for_decl = htab_create_ggc (512, tree_int_map_hash,
-					    tree_int_map_eq, 0);
+  init_priority_for_decl = htab_create_ggc (512, tree_priority_map_hash,
+					    tree_priority_map_eq, 0);
   restrict_base_for_decl = htab_create_ggc (256, tree_map_hash,
 					    tree_map_eq, 0);
 
@@ -4195,18 +4196,18 @@ build_variant_type_copy (tree type)
 /* Return true if the from tree in both tree maps are equal.  */
 
 int
-tree_map_eq (const void *va, const void *vb)
+tree_map_base_eq (const void *va, const void *vb)
 {
-  const struct tree_map  *a = va, *b = vb;
+  const struct tree_map_base  *a = va, *b = vb;
   return (a->from == b->from);
 }
 
 /* Hash a from tree in a tree_map.  */
 
 unsigned int
-tree_map_hash (const void *item)
+tree_map_base_hash (const void *item)
 {
-  return (((const struct tree_map *) item)->hash);
+  return htab_hash_pointer (((const struct tree_map_base *)item)->from);
 }
 
 /* Return true if this tree map structure is marked for garbage collection
@@ -4214,70 +4215,97 @@ tree_map_hash (const void *item)
    structure goes away when the from tree goes away.  */
 
 int
-tree_map_marked_p (const void *p)
+tree_map_base_marked_p (const void *p)
 {
-  tree from = ((struct tree_map *) p)->from;
+  return ggc_marked_p (((struct tree_map_base *) p)->from);
+}
 
-  return ggc_marked_p (from);
+unsigned int
+tree_map_hash (const void *item)
+{
+  return (((const struct tree_map *) item)->hash);
 }
 
-/* Return true if the trees in the tree_int_map *'s VA and VB are equal.  */
+/* Return the initialization priority for DECL.  */
 
-int
-tree_int_map_eq (const void *va, const void *vb)
+priority_type
+decl_init_priority_lookup (tree decl)
 {
-  const struct tree_int_map  *a = va, *b = vb;
-  return (a->from == b->from);
+  struct tree_priority_map *h;
+  struct tree_map_base in;
+
+  gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
+  gcc_assert (TREE_CODE (decl) == VAR_DECL
+	      ? DECL_HAS_INIT_PRIORITY_P (decl)
+	      : DECL_STATIC_CONSTRUCTOR (decl));
+  in.from = decl;
+  h = htab_find (init_priority_for_decl, &in);
+  return h ? h->init : DEFAULT_INIT_PRIORITY;
 }
 
-/* Hash a from tree in the tree_int_map * ITEM.  */
+/* Return the finalization priority for DECL.  */
 
-unsigned int
-tree_int_map_hash (const void *item)
+priority_type
+decl_fini_priority_lookup (tree decl)
 {
-  return htab_hash_pointer (((const struct tree_int_map *)item)->from);
+  struct tree_priority_map *h;
+  struct tree_map_base in;
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  gcc_assert (DECL_STATIC_DESTRUCTOR (decl));
+  in.from = decl;
+  h = htab_find (init_priority_for_decl, &in);
+  return h ? h->fini : DEFAULT_INIT_PRIORITY;
 }
 
-/* Return true if this tree int map structure is marked for garbage collection
-   purposes.  We simply return true if the from tree_int_map *P's from tree is marked, so that this
-   structure goes away when the from tree goes away.  */
+/* Return the initialization and finalization priority information for
+   DECL.  If there is no previous priority information, a freshly
+   allocated structure is returned.  */
 
-int
-tree_int_map_marked_p (const void *p)
+static struct tree_priority_map *
+decl_priority_info (tree decl)
 {
-  tree from = ((struct tree_int_map *) p)->from;
+  struct tree_priority_map in;
+  struct tree_priority_map *h;
+  void **loc;
+
+  in.base.from = decl;
+  loc = htab_find_slot (init_priority_for_decl, &in, INSERT);
+  h = *loc;
+  if (!h)
+    {
+      h = GGC_CNEW (struct tree_priority_map);
+      *loc = h;
+      h->base.from = decl;
+      h->init = DEFAULT_INIT_PRIORITY;
+      h->fini = DEFAULT_INIT_PRIORITY;
+    }
 
-  return ggc_marked_p (from);
+  return h;
 }
-/* Lookup an init priority for FROM, and return it if we find one.  */
 
-unsigned short
-decl_init_priority_lookup (tree from)
+/* Set the initialization priority for DECL to PRIORITY.  */
+
+void
+decl_init_priority_insert (tree decl, priority_type priority)
 {
-  struct tree_int_map *h, in;
-  in.from = from;
+  struct tree_priority_map *h;
 
-  h = htab_find_with_hash (init_priority_for_decl, 
-			   &in, htab_hash_pointer (from));
-  if (h)
-    return h->to;
-  return 0;
-}
+  gcc_assert (VAR_OR_FUNCTION_DECL_P (decl));
+  h = decl_priority_info (decl);
+  h->init = priority;
+}  
 
-/* Insert a mapping FROM->TO in the init priority hashtable.  */
+/* Set the finalization priority for DECL to PRIORITY.  */
 
 void
-decl_init_priority_insert (tree from, unsigned short to)
+decl_fini_priority_insert (tree decl, priority_type priority)
 {
-  struct tree_int_map *h;
-  void **loc;
+  struct tree_priority_map *h;
 
-  h = ggc_alloc (sizeof (struct tree_int_map));
-  h->from = from;
-  h->to = to;
-  loc = htab_find_slot_with_hash (init_priority_for_decl, h, 
-				  htab_hash_pointer (from), INSERT);
-  *(struct tree_int_map **) loc = h;
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  h = decl_priority_info (decl);
+  h->fini = priority;
 }  
 
 /* Look up a restrict qualified base decl for FROM.  */
@@ -4288,7 +4316,7 @@ decl_restrict_base_lookup (tree from)
   struct tree_map *h;
   struct tree_map in;
 
-  in.from = from;
+  in.base.from = from;
   h = htab_find_with_hash (restrict_base_for_decl, &in,
 			   htab_hash_pointer (from));
   return h ? h->to : NULL_TREE;
@@ -4304,7 +4332,7 @@ decl_restrict_base_insert (tree from, tr
 
   h = ggc_alloc (sizeof (struct tree_map));
   h->hash = htab_hash_pointer (from);
-  h->from = from;
+  h->base.from = from;
   h->to = to;
   loc = htab_find_slot_with_hash (restrict_base_for_decl, h, h->hash, INSERT);
   *(struct tree_map **) loc = h;
@@ -4352,7 +4380,7 @@ tree 
 decl_debug_expr_lookup (tree from)
 {
   struct tree_map *h, in;
-  in.from = from;
+  in.base.from = from;
 
   h = htab_find_with_hash (debug_expr_for_decl, &in, htab_hash_pointer (from));
   if (h)
@@ -4370,7 +4398,7 @@ decl_debug_expr_insert (tree from, tree 
 
   h = ggc_alloc (sizeof (struct tree_map));
   h->hash = htab_hash_pointer (from);
-  h->from = from;
+  h->base.from = from;
   h->to = to;
   loc = htab_find_slot_with_hash (debug_expr_for_decl, h, h->hash, INSERT);
   *(struct tree_map **) loc = h;
@@ -4382,7 +4410,7 @@ tree 
 decl_value_expr_lookup (tree from)
 {
   struct tree_map *h, in;
-  in.from = from;
+  in.base.from = from;
 
   h = htab_find_with_hash (value_expr_for_decl, &in, htab_hash_pointer (from));
   if (h)
@@ -4400,7 +4428,7 @@ decl_value_expr_insert (tree from, tree 
 
   h = ggc_alloc (sizeof (struct tree_map));
   h->hash = htab_hash_pointer (from);
-  h->from = from;
+  h->base.from = from;
   h->to = to;
   loc = htab_find_slot_with_hash (value_expr_for_decl, h, h->hash, INSERT);
   *(struct tree_map **) loc = h;
Index: tree.h
===================================================================
--- tree.h	(revision 122239)
+++ tree.h	(working copy)
@@ -2599,13 +2599,6 @@ struct tree_memory_partition_tag GTY(())
    a C99 "extern inline" function.  */
 #define DECL_EXTERNAL(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.decl_flag_2)
 
-/* In a VAR_DECL for a RECORD_TYPE, sets number for non-init_priority
-   initializations.  */
-#define DEFAULT_INIT_PRIORITY 65535
-#define MAX_INIT_PRIORITY 65535
-#define MAX_RESERVED_INIT_PRIORITY 100
-
-
 /* Nonzero in a ..._DECL means this variable is ref'd from a nested function.
    For VAR_DECL nodes, PARM_DECL nodes, and FUNCTION_DECL nodes.
 
@@ -3065,20 +3058,46 @@ extern void decl_debug_expr_insert (tree
 #define SET_DECL_DEBUG_EXPR(NODE, VAL) \
   (decl_debug_expr_insert (VAR_DECL_CHECK (NODE), VAL))
 
+/* An initializationp priority.  */
+typedef unsigned short priority_type;
 
-extern unsigned short decl_init_priority_lookup (tree);
-extern void decl_init_priority_insert (tree, unsigned short);
-
-/* 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.  Only used by C++ FE*/
-
+extern priority_type decl_init_priority_lookup (tree);
+extern priority_type decl_fini_priority_lookup (tree);
+extern void decl_init_priority_insert (tree, priority_type);
+extern void decl_fini_priority_insert (tree, priority_type);
+
+/* In a non-local VAR_DECL with static storage duration, true if the
+   variable has an initialization priority.  If false, the variable
+   will be initialized at the DEFAULT_INIT_PRIORITY.  */
 #define DECL_HAS_INIT_PRIORITY_P(NODE) \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.init_priority_p)
+
+/* For a VAR_DECL or FUNCTION_DECL with DECL_HAS_INIT_PRIORITY_P set,
+   the initialization priority of NODE.  */
 #define DECL_INIT_PRIORITY(NODE) \
-  (decl_init_priority_lookup (VAR_DECL_CHECK (NODE)))
+  (decl_init_priority_lookup (NODE))
+/* Set the initialization priority for NODE to VAL.  */
 #define SET_DECL_INIT_PRIORITY(NODE, VAL) \
-  (decl_init_priority_insert (VAR_DECL_CHECK (NODE), VAL))
+  (decl_init_priority_insert (NODE, VAL))
+
+/* For a FUNCTION_DECL with DECL_HAS_INIT_PRIORITY_P set, the
+   finalization priority of NODE.  */
+#define DECL_FINI_PRIORITY(NODE) \
+  (decl_fini_priority_lookup (NODE))
+/* Set the finalization priority for NODE to VAL.  */
+#define SET_DECL_FINI_PRIORITY(NODE, VAL) \
+  (decl_fini_priority_insert (NODE, VAL))
+
+/* The initialization priority for entities for which no explicit
+   initialization priority has been specified.  */
+#define DEFAULT_INIT_PRIORITY 65535
+
+/* The maximum allowed initialization priority.  */
+#define MAX_INIT_PRIORITY 65535
+
+/* The largest priority value reserved for use by system runtime
+   libraries.  */
+#define MAX_RESERVED_INIT_PRIORITY 100
 
 /* In a VAR_DECL, the model to use if the data should be allocated from
    thread-local storage.  */
@@ -4800,26 +4819,53 @@ extern tree get_base_address (tree t);
 extern void vect_set_verbosity_level (const char *);
 
 /* In tree.c.  */
+
+struct tree_map_base GTY(())
+{
+  tree from;
+};
+
+extern int tree_map_base_eq (const void *, const void *);
+extern unsigned int tree_map_base_hash (const void *);
+extern int tree_map_base_marked_p (const void *);
+
+/* Map from a tree to another tree.  */
+
 struct tree_map GTY(())
 {
+  struct tree_map_base base;
   unsigned int hash;
-  tree from;
   tree to;
 };
 
+#define tree_map_eq tree_map_base_eq
 extern unsigned int tree_map_hash (const void *);
-extern int tree_map_marked_p (const void *);
-extern int tree_map_eq (const void *, const void *);
+#define tree_map_marked_p tree_map_base_marked_p
+
+/* Map from a tree to an int.  */
 
 struct tree_int_map GTY(())
 {
-  tree from;
+  struct tree_map_base base;
   unsigned int to;
 };
 
-extern unsigned int tree_int_map_hash (const void *);
-extern int tree_int_map_eq (const void *, const void *);
-extern int tree_int_map_marked_p (const void *);
+#define tree_int_map_eq tree_map_base_eq
+#define tree_int_map_hash tree_map_base_hash
+#define tree_int_map_marked_p tree_map_base_marked_p
+
+/* Map from a tree to initialization/finalization priorities.  */
+
+struct tree_priority_map GTY(())
+{
+  struct tree_map_base base;
+  priority_type init;
+  priority_type fini;
+};
+
+#define tree_priority_map_eq tree_map_base_eq
+#define tree_priority_map_hash tree_map_base_hash
+#define tree_priority_map_marked_p tree_map_base_marked_p
 
 /* In tree-ssa-address.c.  */
 extern tree tree_mem_ref_addr (tree, tree);
Index: c-decl.c
===================================================================
--- c-decl.c	(revision 122239)
+++ c-decl.c	(working copy)
@@ -6828,28 +6828,6 @@ finish_function (void)
   cfun = NULL;
   current_function_decl = NULL;
 }
-
-/* Generate the RTL for the body of FNDECL.  */
-
-void
-c_expand_body (tree fndecl)
-{
-
-  if (!DECL_INITIAL (fndecl)
-      || DECL_INITIAL (fndecl) == error_mark_node)
-    return;
-
-  tree_rest_of_compilation (fndecl);
-
-  if (DECL_STATIC_CONSTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
-				 DEFAULT_INIT_PRIORITY);
-  if (DECL_STATIC_DESTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
-				DEFAULT_INIT_PRIORITY);
-}
 
 /* Check the declarations given in a for-loop for satisfying the C99
    constraints.  If exactly one such decl is found, return it.  */
Index: varasm.c
===================================================================
--- varasm.c	(revision 122239)
+++ varasm.c	(working copy)
@@ -343,7 +343,7 @@ emutls_decl (tree decl)
      of the decl's pointer.  In emutls_finish we iterate through the
      hash table, and we want this traversal to be predictable.  */
   in.hash = htab_hash_string (IDENTIFIER_POINTER (name));
-  in.from = decl;
+  in.base.from = decl;
   loc = htab_find_slot_with_hash (emutls_htab, &in, in.hash, INSERT);
   h = *loc;
   if (h != NULL)
@@ -355,7 +355,7 @@ emutls_decl (tree decl)
 
       h = ggc_alloc (sizeof (struct tree_map));
       h->hash = in.hash;
-      h->from = decl;
+      h->base.from = decl;
       h->to = to;
       *(struct tree_map **) loc = h;
 
@@ -394,9 +394,9 @@ emutls_common_1 (void **loc, void *xstmt
   tree args, x, *pstmts = (tree *) xstmts;
   tree word_type_node;
 
-  if (! DECL_COMMON (h->from)
-      || (DECL_INITIAL (h->from)
-	  && DECL_INITIAL (h->from) != error_mark_node))
+  if (! DECL_COMMON (h->base.from)
+      || (DECL_INITIAL (h->base.from)
+	  && DECL_INITIAL (h->base.from) != error_mark_node))
     return 1;
 
   word_type_node = lang_hooks.types.type_for_mode (word_mode, 1);
@@ -407,9 +407,9 @@ emutls_common_1 (void **loc, void *xstmt
      output.  */
   x = null_pointer_node;
   args = tree_cons (NULL, x, NULL);
-  x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->from));
+  x = build_int_cst (word_type_node, DECL_ALIGN_UNIT (h->base.from));
   args = tree_cons (NULL, x, args);
-  x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->from));
+  x = fold_convert (word_type_node, DECL_SIZE_UNIT (h->base.from));
   args = tree_cons (NULL, x, args);
   x = build_fold_addr_expr (h->to);
   args = tree_cons (NULL, x, args);
Index: lambda-code.c
===================================================================
--- lambda-code.c	(revision 122239)
+++ lambda-code.c	(working copy)
@@ -2153,7 +2153,7 @@ replace_uses_equiv_to_x_with_y (struct l
       /* Use REPLACEMENTS hash table to cache already created
 	 temporaries.  */
       in.hash = htab_hash_pointer (use);
-      in.from = use;
+      in.base.from = use;
       h = htab_find_with_hash (replacements, &in, in.hash);
       if (h != NULL)
 	{
@@ -2198,7 +2198,7 @@ replace_uses_equiv_to_x_with_y (struct l
       SET_USE (use_p, var);
       h = ggc_alloc (sizeof (struct tree_map));
       h->hash = in.hash;
-      h->from = use;
+      h->base.from = use;
       h->to = var;
       loc = htab_find_slot_with_hash (replacements, h, in.hash, INSERT);
       gcc_assert ((*(struct tree_map **)loc) == NULL);
Index: c-common.c
===================================================================
--- c-common.c	(revision 122239)
+++ c-common.c	(working copy)
@@ -598,9 +598,9 @@ const struct attribute_spec c_common_att
 			      handle_const_attribute },
   { "transparent_union",      0, 0, false, false, false,
 			      handle_transparent_union_attribute },
-  { "constructor",            0, 0, true,  false, false,
+  { "constructor",            0, 1, true,  false, false,
 			      handle_constructor_attribute },
-  { "destructor",             0, 0, true,  false, false,
+  { "destructor",             0, 1, true,  false, false,
 			      handle_destructor_attribute },
   { "mode",                   1, 1, false,  true, false,
 			      handle_mode_attribute },
@@ -4220,6 +4220,29 @@ c_expand_expr (tree exp, rtx target, enu
     }
 }
 
+
+/* Generate the RTL for the body of FNDECL.  */
+
+void
+c_expand_body (tree fndecl)
+{
+
+  if (!DECL_INITIAL (fndecl)
+      || DECL_INITIAL (fndecl) == error_mark_node)
+    return;
+
+  tree_rest_of_compilation (fndecl);
+
+  if (DECL_STATIC_CONSTRUCTOR (fndecl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
+				 decl_init_priority_lookup (fndecl));
+  if (DECL_STATIC_DESTRUCTOR (fndecl)
+      && targetm.have_ctors_dtors)
+    targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
+				decl_fini_priority_lookup (fndecl));
+}
+
 /* Hook used by staticp to handle language-specific tree codes.  */
 
 tree
@@ -4655,12 +4678,56 @@ handle_transparent_union_attribute (tree
   return NULL_TREE;
 }
 
+/* Subroutine of handle_{con,de}structor_attribute.  Evaluate ARGS to
+   get the requested priority for a constructor or destructor,
+   possibly issuing diagnostics for invalid or reserved
+   priorities.  */
+
+static priority_type
+get_priority (tree args, bool is_destructor)
+{
+  HOST_WIDE_INT pri;
+
+  if (!args)
+    return DEFAULT_INIT_PRIORITY;
+
+  if (!host_integerp (TREE_VALUE (args), /*pos=*/0))
+    goto invalid;
+
+  pri = tree_low_cst (TREE_VALUE (args), /*pos=*/0);
+  if (pri < 0 || pri > MAX_INIT_PRIORITY)
+    goto invalid;
+
+  if (pri <= MAX_RESERVED_INIT_PRIORITY)
+    {
+      if (is_destructor)
+	warning (0,
+		 "destructor priorities from 0 to %d are reserved "
+		 "for the implementation", 
+		 MAX_RESERVED_INIT_PRIORITY);
+      else
+	warning (0,
+		 "constructor priorities from 0 to %d are reserved "
+		 "for the implementation", 
+		 MAX_RESERVED_INIT_PRIORITY);
+    }
+  return pri;
+
+ invalid:
+  if (is_destructor)
+    error ("destructor priorities must be integers from 0 to %d inclusive",
+	   MAX_INIT_PRIORITY);
+  else
+    error ("constructor priorities must be integers from 0 to %d inclusive",
+	   MAX_INIT_PRIORITY);
+  return DEFAULT_INIT_PRIORITY;
+}
+
 /* Handle a "constructor" attribute; arguments as in
    struct attribute_spec.handler.  */
 
 static tree
-handle_constructor_attribute (tree *node, tree name,
-			      tree ARG_UNUSED (args),
+handle_constructor_attribute (tree *node, tree name, tree args,
 			      int ARG_UNUSED (flags),
 			      bool *no_add_attrs)
 {
@@ -4671,7 +4738,10 @@ handle_constructor_attribute (tree *node
       && TREE_CODE (type) == FUNCTION_TYPE
       && decl_function_context (decl) == 0)
     {
+      priority_type priority;
       DECL_STATIC_CONSTRUCTOR (decl) = 1;
+      priority = get_priority (args, /*is_destructor=*/false);
+      SET_DECL_INIT_PRIORITY (decl, priority);
       TREE_USED (decl) = 1;
     }
   else
@@ -4687,8 +4757,7 @@ handle_constructor_attribute (tree *node
    struct attribute_spec.handler.  */
 
 static tree
-handle_destructor_attribute (tree *node, tree name,
-			     tree ARG_UNUSED (args),
+handle_destructor_attribute (tree *node, tree name, tree args,
 			     int ARG_UNUSED (flags),
 			     bool *no_add_attrs)
 {
@@ -4699,7 +4768,10 @@ handle_destructor_attribute (tree *node,
       && TREE_CODE (type) == FUNCTION_TYPE
       && decl_function_context (decl) == 0)
     {
+      priority_type priority;
       DECL_STATIC_DESTRUCTOR (decl) = 1;
+      priority = get_priority (args, /*is_destructor=*/true);
+      SET_DECL_FINI_PRIORITY (decl, priority);
       TREE_USED (decl) = 1;
     }
   else
Index: c-common.h
===================================================================
--- c-common.h	(revision 122239)
+++ c-common.h	(working copy)
@@ -810,6 +810,7 @@ extern tree lookup_name (tree);
 extern bool vector_types_convertible_p (tree t1, tree t2, bool emit_lax_note);
 
 extern rtx c_expand_expr (tree, rtx, enum machine_mode, int, rtx *);
+extern void c_expand_body (tree);
 
 extern tree c_staticp (tree);
 
Index: tree-ssa-structalias.c
===================================================================
--- tree-ssa-structalias.c	(revision 122239)
+++ tree-ssa-structalias.c	(working copy)
@@ -330,7 +330,7 @@ static tree
 heapvar_lookup (tree from)
 {
   struct tree_map *h, in;
-  in.from = from;
+  in.base.from = from;
 
   h = htab_find_with_hash (heapvar_for_stmt, &in, htab_hash_pointer (from));
   if (h)
@@ -349,7 +349,7 @@ heapvar_insert (tree from, tree to)
 
   h = ggc_alloc (sizeof (struct tree_map));
   h->hash = htab_hash_pointer (from);
-  h->from = from;
+  h->base.from = from;
   h->to = to;
   loc = htab_find_slot_with_hash (heapvar_for_stmt, h, h->hash, INSERT);
   *(struct tree_map **) loc = h;
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 122239)
+++ tree-cfg.c	(working copy)
@@ -4606,7 +4606,7 @@ move_stmt_r (tree *tp, int *walk_subtree
 	  if (p->new_label_map)
 	    {
 	      struct tree_map in, *out;
-	      in.from = t;
+	      in.base.from = t;
 	      out = htab_find_with_hash (p->new_label_map, &in, DECL_UID (t));
 	      if (out)
 		*tp = t = out->to;
@@ -4795,7 +4795,7 @@ new_label_mapper (tree decl, void *data)
 
   m = xmalloc (sizeof (struct tree_map));
   m->hash = DECL_UID (decl);
-  m->from = decl;
+  m->base.from = decl;
   m->to = create_artificial_label ();
   LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
 
Index: cp/cp-objcp-common.c
===================================================================
--- cp/cp-objcp-common.c	(revision 122239)
+++ cp/cp-objcp-common.c	(working copy)
@@ -228,7 +228,7 @@ tree
 decl_shadowed_for_var_lookup (tree from)
 {
   struct tree_map *h, in;
-  in.from = from;
+  in.base.from = from;
 
   h = (struct tree_map *) htab_find_with_hash (shadowed_var_for_decl, &in,
 					       htab_hash_pointer (from));
@@ -247,7 +247,7 @@ decl_shadowed_for_var_insert (tree from,
 
   h = GGC_NEW (struct tree_map);
   h->hash = htab_hash_pointer (from);
-  h->from = from;
+  h->base.from = from;
   h->to = to;
   loc = htab_find_slot_with_hash (shadowed_var_for_decl, h, h->hash, INSERT);
   *(struct tree_map **) loc = h;
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 122239)
+++ cp/cp-tree.h	(working copy)
@@ -3479,11 +3479,6 @@ extern int at_eof;
    TREE_PURPOSE slot.  */
 extern GTY(()) tree static_aggregates;
 
-/* Functions called along with real static constructors and destructors.  */
-
-extern GTY(()) tree static_ctors;
-extern GTY(()) tree static_dtors;
-
 enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
 
 /* These are uses as bits in flags passed to various functions to
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 122239)
+++ cp/semantics.c	(working copy)
@@ -3099,7 +3099,7 @@ expand_body (tree fn)
      generating trees for a function.  */
   gcc_assert (function_depth == 0);
 
-  tree_rest_of_compilation (fn);
+  c_expand_body (fn);
 
   current_function_decl = saved_function;
 
@@ -3159,18 +3159,6 @@ expand_or_defer_fn (tree fn)
       return;
     }
 
-  /* If this function is marked with the constructor attribute, add it
-     to the list of functions to be called along with constructors
-     from static duration objects.  */
-  if (DECL_STATIC_CONSTRUCTOR (fn))
-    static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
-
-  /* If this function is marked with the destructor attribute, add it
-     to the list of functions to be called along with destructors from
-     static duration objects.  */
-  if (DECL_STATIC_DESTRUCTOR (fn))
-    static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
-
   /* We make a decision about linkage for these functions at the end
      of the compilation.  Until that point, we do not want the back
      end to output them -- but we do want it to see the bodies of
Index: cp/decl2.c
===================================================================
--- cp/decl2.c	(revision 122239)
+++ cp/decl2.c	(working copy)
@@ -97,11 +97,6 @@ static GTY(()) VEC(tree,gc) *deferred_fn
 
 int at_eof;
 
-/* Functions called along with real static constructors and destructors.  */
-
-tree static_ctors;
-tree static_dtors;
-
 
 
 /* Return a member function type (a METHOD_TYPE), given FNTYPE (a
@@ -2847,7 +2842,7 @@ generate_ctor_or_dtor_function (bool con
       && constructor_p && objc_static_init_needed_p ())
     {
       body = start_objects (function_key, priority);
-      static_ctors = objc_generate_static_init_call (static_ctors);
+      objc_generate_static_init_call (NULL_TREE);
     }
 
   /* Call the static storage duration function with appropriate
@@ -2870,29 +2865,6 @@ generate_ctor_or_dtor_function (bool con
 	}
     }
 
-  /* 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))
-	{
-	  fndecl = TREE_VALUE (fns);
-
-	  /* Calls to pure/const functions will expand to nothing.  */
-	  if (! (flags_from_decl_or_type (fndecl) & (ECF_CONST | ECF_PURE)))
-	    {
-	      if (! body)
-		body = start_objects (function_key, priority);
-	      finish_expr_stmt (build_function_call (fndecl, NULL_TREE));
-	    }
-	}
-    }
-
   /* Close out the function.  */
   if (body)
     finish_objects (function_key, priority, body);
@@ -2910,11 +2882,9 @@ generate_ctor_and_dtor_functions_for_pri
 
   /* Generate the functions themselves, but only if they are really
      needed.  */
-  if (pi->initializations_p
-      || (priority == DEFAULT_INIT_PRIORITY && static_ctors))
+  if (pi->initializations_p)
     generate_ctor_or_dtor_function (/*constructor_p=*/true, priority, locus);
-  if (pi->destructions_p
-      || (priority == DEFAULT_INIT_PRIORITY && static_dtors))
+  if (pi->destructions_p)
     generate_ctor_or_dtor_function (/*constructor_p=*/false, priority, locus);
 
   /* Keep iterating.  */
@@ -3309,17 +3279,11 @@ cp_write_global_declarations (void)
     splay_tree_foreach (priority_info_map,
 			generate_ctor_and_dtor_functions_for_priority,
 			/*data=*/&locus);
-  else
-    {
-      /* If we have a ctor or this is obj-c++ and we need a static init,
-	 call generate_ctor_or_dtor_function.  */
-      if (static_ctors || (c_dialect_objc () && objc_static_init_needed_p ()))
-	generate_ctor_or_dtor_function (/*constructor_p=*/true,
-					DEFAULT_INIT_PRIORITY, &locus);
-      if (static_dtors)
-	generate_ctor_or_dtor_function (/*constructor_p=*/false,
-					DEFAULT_INIT_PRIORITY, &locus);
-    }
+  else if (c_dialect_objc () && objc_static_init_needed_p ())
+    /* If this is obj-c++ and we need a static init, call
+       generate_ctor_or_dtor_function.  */
+    generate_ctor_or_dtor_function (/*constructor_p=*/true,
+				    DEFAULT_INIT_PRIORITY, &locus);
 
   /* We're done with the splay-tree now.  */
   if (priority_info_map)
Index: c-tree.h
===================================================================
--- c-tree.h	(revision 122239)
+++ c-tree.h	(working copy)
@@ -441,7 +441,6 @@ extern int global_bindings_p (void);
 extern void push_scope (void);
 extern tree pop_scope (void);
 extern void insert_block (tree);
-extern void c_expand_body (tree);
 
 extern void c_init_decl_processing (void);
 extern void c_dup_lang_specific_decl (tree);
Index: ada/decl.c
===================================================================
--- ada/decl.c	(revision 122239)
+++ ada/decl.c	(working copy)
@@ -5890,7 +5890,7 @@ annotate_value (tree gnu_size)
       if (!annotate_value_cache)
         annotate_value_cache = htab_create_ggc (512, tree_int_map_hash,
 					        tree_int_map_eq, 0);
-      in.from = gnu_size;
+      in.base.from = gnu_size;
       h = (struct tree_int_map **)
 	    htab_find_slot (annotate_value_cache, &in, INSERT);
 
Index: testsuite/gcc.dg/initpri1.c
===================================================================
--- testsuite/gcc.dg/initpri1.c	(revision 0)
+++ testsuite/gcc.dg/initpri1.c	(revision 0)
@@ -0,0 +1,62 @@
+/* { dg-do run { target init_priority } } */
+
+extern void abort ();
+
+int i;
+int j;
+
+void c1() __attribute__((constructor (500)));
+void c2() __attribute__((constructor (700)));
+void c3() __attribute__((constructor (600)));
+
+void c1() {
+  if (i++ != 0)
+    abort ();
+}
+
+void c2() {
+  if (i++ != 2)
+    abort ();
+}
+
+void c3() {
+  if (i++ != 1)
+    abort ();
+}
+
+void d1() __attribute__((destructor (500)));
+void d2() __attribute__((destructor (700)));
+void d3() __attribute__((destructor (600)));
+
+void d1() {
+  if (--i != 0)
+    abort ();
+}
+
+void d2() {
+  if (--i != 2)
+    abort ();
+}
+
+void d3() {
+  if (j != 2)
+    abort ();
+  if (--i != 1)
+    abort ();
+}
+
+void cd4() __attribute__((constructor (800), destructor (800)));
+
+void cd4() {
+  if (i != 3)
+    abort ();
+  ++j;
+}
+
+int main () {
+  if (i != 3)
+    return 1;
+  if (j != 1)
+    abort ();
+  return 0;
+}
Index: testsuite/gcc.dg/initpri2.c
===================================================================
--- testsuite/gcc.dg/initpri2.c	(revision 0)
+++ testsuite/gcc.dg/initpri2.c	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile { target init_priority } } */
+
+/* Priorities must be in the range [0, 65535].  */
+void c1()
+     __attribute__((constructor (-1))); /* { dg-error "priorities" } */
+void c2() 
+     __attribute__((constructor (65536))); /* { dg-error "priorities" } */
+void d1() 
+     __attribute__((destructor (-1))); /* { dg-error "priorities" } */
+void d2() 
+     __attribute__((destructor (65536))); /* { dg-error "priorities" } */
+
+/* Priorities 0-100 are reserved for system libraries.  */
+void c3() 
+     __attribute__((constructor (50))); /* { dg-warning "reserved" } */
+void d3() 
+     __attribute__((constructor (50))); /* { dg-warning "reserved" } */
+
Index: testsuite/g++.dg/special/initpri1.C
===================================================================
--- testsuite/g++.dg/special/initpri1.C	(revision 0)
+++ testsuite/g++.dg/special/initpri1.C	(revision 0)
@@ -0,0 +1,62 @@
+/* { dg-do run { target init_priority } } */
+
+extern "C" void abort ();
+
+int i;
+int j;
+
+void c1() __attribute__((constructor (500)));
+void c2() __attribute__((constructor (700)));
+void c3() __attribute__((constructor (600)));
+
+void c1() {
+  if (i++ != 0)
+    abort ();
+}
+
+void c2() {
+  if (i++ != 2)
+    abort ();
+}
+
+void c3() {
+  if (i++ != 1)
+    abort ();
+}
+
+void d1() __attribute__((destructor (500)));
+void d2() __attribute__((destructor (700)));
+void d3() __attribute__((destructor (600)));
+
+void d1() {
+  if (--i != 0)
+    abort ();
+}
+
+void d2() {
+  if (--i != 2)
+    abort ();
+}
+
+void d3() {
+  if (j != 2)
+    abort ();
+  if (--i != 1)
+    abort ();
+}
+
+void cd4() __attribute__((constructor (800), destructor (800)));
+
+void cd4() {
+  if (i != 3)
+    abort ();
+  ++j;
+}
+
+int main () {
+  if (i != 3)
+    return 1;
+  if (j != 1)
+    abort ();
+  return 0;
+}
Index: testsuite/g++.dg/special/initpri2.C
===================================================================
--- testsuite/g++.dg/special/initpri2.C	(revision 0)
+++ testsuite/g++.dg/special/initpri2.C	(revision 0)
@@ -0,0 +1,18 @@
+/* { dg-do compile { target init_priority } } */
+
+/* Priorities must be in the range [0, 65535].  */
+void c1()
+     __attribute__((constructor (-1))); /* { dg-error "priorities" } */
+void c2() 
+     __attribute__((constructor (65536))); /* { dg-error "priorities" } */
+void d1() 
+     __attribute__((destructor (-1))); /* { dg-error "priorities" } */
+void d2() 
+     __attribute__((destructor (65536))); /* { dg-error "priorities" } */
+
+/* Priorities 0-100 are reserved for system libraries.  */
+void c3() 
+     __attribute__((constructor (50))); /* { dg-warning "reserved" } */
+void d3() 
+     __attribute__((constructor (50))); /* { dg-warning "reserved" } */
+
Index: testsuite/g++.dg/special/conpr-1.C
===================================================================
--- testsuite/g++.dg/special/conpr-1.C	(revision 122239)
+++ testsuite/g++.dg/special/conpr-1.C	(working copy)
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
 
 #include <stdlib.h>
 
Index: testsuite/g++.dg/special/conpr-2.C
===================================================================
--- testsuite/g++.dg/special/conpr-2.C	(revision 122239)
+++ testsuite/g++.dg/special/conpr-2.C	(working copy)
@@ -1,5 +1,4 @@
-/* This doesn't work on solaris2 for reasons described in PR 6482.  */
-/* { dg-do run { xfail *-*-solaris2* } } */
+/* { dg-do run { target init_priority } } */
 /* { dg-additional-sources "conpr-2a.cc" } */
 
 #include <stdlib.h>
Index: testsuite/g++.dg/special/conpr-3.C
===================================================================
--- testsuite/g++.dg/special/conpr-3.C	(revision 122239)
+++ testsuite/g++.dg/special/conpr-3.C	(working copy)
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
 /* { dg-additional-sources "conpr-3a.cc conpr-3b.cc" } */
 
 #include <stdlib.h>
Index: testsuite/g++.dg/special/conpr-4.C
===================================================================
--- testsuite/g++.dg/special/conpr-4.C	(revision 122239)
+++ testsuite/g++.dg/special/conpr-4.C	(working copy)
@@ -1,4 +1,4 @@
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
 /* { dg-additional-sources "conpr-3b.cc conpr-3a.cc" } */
 
 #include <stdlib.h>
Index: testsuite/g++.dg/special/initp1.C
===================================================================
--- testsuite/g++.dg/special/initp1.C	(revision 122239)
+++ testsuite/g++.dg/special/initp1.C	(working copy)
@@ -1,5 +1,4 @@
-/* This doesn't work on solaris2 for reasons described in PR 6482.  */
-/* { dg-do run { xfail *-*-solaris2* } } */
+/* { dg-do run { target init_priority } } */
 #include <stdlib.h>
 
 class Two {
Index: testsuite/g++.dg/special/ecos.exp
===================================================================
--- testsuite/g++.dg/special/ecos.exp	(revision 122239)
+++ testsuite/g++.dg/special/ecos.exp	(working copy)
@@ -24,16 +24,6 @@
 # Load support procs.
 load_lib g++-dg.exp
 
-# Test for whether or not __attribute__((init_priority)) is supported
-# by the platform.
-
-set comp_output [g++_target_compile \
-		"$srcdir/$subdir/initp1.C" "initp1.S" assembly ""]
-remove-build-file "initp1.S"
-if { [string match "*init_priority*" $comp_output] } {
-  return 0
-}
-
 # Initialize 'dg'.
 dg-init
 
Index: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp	(revision 122273)
+++ testsuite/lib/target-supports.exp	(working copy)
@@ -2089,6 +2089,23 @@ proc check_effective_target_dummy_wcsfti
     return [check_effective_target_uclibc]
 }
 
+# Return 1 if constructors with initialization priority arguments are
+# supposed on this target.
+
+proc check_effective_target_init_priority {} {
+    # On Solaris2, initialization priorities are only supported with
+    # GNU ld, but the compiler accepts them even when using Sun ld.
+    # For more information, see PR 6482.
+    if { [istarget *-solaris2*] } {
+	return 1
+    }
+
+    return [check_no_compiler_messages init_priority assembly "
+	void f() __attribute__((constructor (1000)));
+	void f() \{\}
+    "]
+}
+
 # Return 1 if the target matches the effective target 'arg', 0 otherwise.
 # This can be used with any check_* proc that takes no argument and
 # returns only 1 or 0.  It could be used with check_* procs that take



More information about the Gcc-patches mailing list