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.
* 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.
* decl.c (annotate_value): Adjust for refactoring of tree_map
hierarchy.
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@122315
138bc75d-0d04-0410-961f-
82ee72b054a4
+2007-02-25 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 Jan Hubicka <jh@suse.cz>
PR middle-end/30509
+2007-02-24 Mark Mitchell <mark@codesourcery.com>
+
+ * decl.c (annotate_value): Adjust for refactoring of tree_map
+ hierarchy.
+
2007-02-21 Ed Schonberg <schonberg@adacore.com>
PR ada/18819
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);
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 },
}
}
+
+/* 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
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)
{
&& 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
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)
{
&& 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
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);
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);
-}
\f
/* Check the declarations given in a for-loop for satisfying the C99
constraints. If exactly one such decl is found, return it. */
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);
+2007-02-25 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-23 Richard Guenther <rguenther@suse.de>
* class.c (note_name_declared_in_class): Make declaration
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));
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;
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
int at_eof;
-/* Functions called along with real static constructors and destructors. */
-
-tree static_ctors;
-tree static_dtors;
-
\f
/* Return a member function type (a METHOD_TYPE), given FNTYPE (a
&& 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
}
}
- /* 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);
/* 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. */
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)
generating trees for a function. */
gcc_assert (function_depth == 0);
- tree_rest_of_compilation (fn);
+ c_expand_body (fn);
current_function_decl = saved_function;
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
@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
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
/* 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)
{
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);
+2007-02-25 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.
+
2007-02-24 Jan Hubicka <jh@suse.cz>
* gcc.c-torture/execute/pr30778.c: New testcase.
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
#include <stdlib.h>
-/* 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>
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
/* { dg-additional-sources "conpr-3a.cc conpr-3b.cc" } */
#include <stdlib.h>
-/* { dg-do run } */
+/* { dg-do run { target init_priority } } */
/* { dg-additional-sources "conpr-3b.cc conpr-3a.cc" } */
#include <stdlib.h>
# 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
-/* 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 {
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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" } */
+
--- /dev/null
+/* { 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;
+}
--- /dev/null
+/* { 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" } */
+
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
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;
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);
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)
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;
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)))
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);
/* 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
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. */
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;
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;
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)
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;
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)
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;
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.
#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. */
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);
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)
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;
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);
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);