static void finish_constructor_body PROTO((void));
static void finish_destructor_body PROTO((void));
static tree create_array_type_for_decl PROTO((tree, tree, tree));
+static tree get_atexit_node PROTO((void));
+static tree get_dso_handle_node PROTO((void));
+static tree start_cleanup_fn PROTO((void));
+static void end_cleanup_fn PROTO((void));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PROTO((void));
cp_finish_decl (decl, init, asmspec_tree, 0);
}
+/* Returns a declaration for a VAR_DECL as if:
+
+ extern "C" TYPE NAME;
+
+ had been seen. Used to create compiler-generated global
+ variables. */
+
+tree
+declare_global_var (name, type)
+ tree name;
+ tree type;
+{
+ tree decl;
+
+ push_to_top_level ();
+ decl = build_decl (VAR_DECL, name, type);
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ pushdecl (decl);
+ cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
+ pop_from_top_level ();
+
+ return decl;
+}
+
+/* Returns a pointer to the `atexit' function. Note that if
+ FLAG_USE_CXA_ATEXIT is non-zero, then this will actually be the new
+ `__cxa_atexit' function specified in the IA64 C++ ABI. */
+
+static tree
+get_atexit_node ()
+{
+ tree atexit_fndecl;
+ tree arg_types;
+ tree fn_type;
+ tree fn_ptr_type;
+ const char *name;
+
+ if (atexit_node)
+ return atexit_node;
+
+ if (flag_use_cxa_atexit)
+ {
+ /* The declaration for `__cxa_atexit' is:
+
+ int __cxa_atexit (void (*)(void *), void *, void *)
+
+ We build up the argument types and then then function type
+ itself. */
+
+ /* First, build the pointer-to-function type for the first
+ argument. */
+ arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ fn_type = build_function_type (void_type_node, arg_types);
+ fn_ptr_type = build_pointer_type (fn_type);
+ /* Then, build the rest of the argument types. */
+ arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ arg_types = tree_cons (NULL_TREE, ptr_type_node, arg_types);
+ arg_types = tree_cons (NULL_TREE, fn_ptr_type, arg_types);
+ /* And the final __cxa_atexit type. */
+ fn_type = build_function_type (integer_type_node, arg_types);
+ fn_ptr_type = build_pointer_type (fn_type);
+ name = "__cxa_atexit";
+ }
+ else
+ {
+ /* The declaration for `atexit' is:
+
+ int atexit (void (*)());
+
+ We build up the argument types and then then function type
+ itself. */
+ fn_type = build_function_type (void_type_node, void_list_node);
+ fn_ptr_type = build_pointer_type (fn_type);
+ arg_types = tree_cons (NULL_TREE, fn_ptr_type, void_list_node);
+ /* Build the final atexit type. */
+ fn_type = build_function_type (integer_type_node, arg_types);
+ name = "atexit";
+ }
+
+ /* Now, build the function declaration. */
+ push_lang_context (lang_name_c);
+ atexit_fndecl = define_function (name, fn_type, /*pfn=*/0, NULL_PTR);
+ mark_used (atexit_fndecl);
+ pop_lang_context ();
+ atexit_node = default_conversion (atexit_fndecl);
+
+ return atexit_node;
+}
+
+/* Returns the __dso_handle VAR_DECL. */
+
+static tree
+get_dso_handle_node ()
+{
+ if (dso_handle_node)
+ return dso_handle_node;
+
+ /* Declare the variable. */
+ dso_handle_node = declare_global_var (get_identifier ("__dso_handle"),
+ ptr_type_node);
+
+ return dso_handle_node;
+}
+
+/* Begin a new function with internal linkage whose job will be simply
+ to destroy some particular variable. */
+
+static tree
+start_cleanup_fn ()
+{
+ static int counter = 0;
+ int old_interface_unknown = interface_unknown;
+ char name[32];
+ tree parmtypes;
+ tree fntype;
+ tree fndecl;
+
+ push_to_top_level ();
+
+ /* No need to mangle this. */
+ push_lang_context (lang_name_c);
+
+ interface_unknown = 1;
+
+ /* Build the parameter-types. */
+ parmtypes = void_list_node;
+ /* Functions passed to __cxa_atexit take an additional parameter.
+ We'll just ignore it. After we implement the new calling
+ convention for destructors, we can eliminate the use of
+ additional cleanup functions entirely in the -fnew-abi case. */
+ if (flag_use_cxa_atexit)
+ parmtypes = tree_cons (NULL_TREE, ptr_type_node, parmtypes);
+ /* Build the function type itself. */
+ fntype = build_function_type (void_type_node, parmtypes);
+ /* Build the name of the function. */
+ sprintf (name, "__tcf_%d", counter++);
+ /* Build the function declaration. */
+ fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
+ /* It's a function with internal linkage, generated by the
+ compiler. */
+ TREE_PUBLIC (fndecl) = 0;
+ DECL_ARTIFICIAL (fndecl) = 1;
+ /* Build the parameter. */
+ if (flag_use_cxa_atexit)
+ {
+ tree parmdecl;
+
+ parmdecl = build_decl (PARM_DECL, NULL_TREE, ptr_type_node);
+ DECL_CONTEXT (parmdecl) = fndecl;
+ DECL_ARG_TYPE (parmdecl) = ptr_type_node;
+ TREE_USED (parmdecl) = 1;
+ DECL_ARGUMENTS (fndecl) = parmdecl;
+ }
+
+ start_function (/*specs=*/NULL_TREE, fndecl, NULL_TREE, SF_PRE_PARSED);
+ do_pushlevel ();
+
+ interface_unknown = old_interface_unknown;
+
+ pop_lang_context ();
+
+ return current_function_decl;
+}
+
+/* Finish the cleanup function begun by start_cleanup_fn. */
+
+static void
+end_cleanup_fn ()
+{
+ do_poplevel ();
+
+ expand_body (finish_function (lineno, 0));
+
+ pop_from_top_level ();
+}
+
/* Generate code to handle the destruction of the function-scoped
static variable DECL. */
destroy_local_static (decl)
tree decl;
{
- tree cleanup, fcall;
+ tree cleanup;
tree compound_stmt;
- int saved_flag_access_control;
+ tree args;
+ tree fcall;
- if (atexit_node == 0)
- {
- tree atexit_fndecl, PFV, pfvlist;
-
- PFV = build_pointer_type (build_function_type
- (void_type_node, void_list_node));
-
- pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+ int saved_flag_access_control;
- push_lang_context (lang_name_c);
- /* Note that we do not call pushdecl for this function;
- there's no reason that this declaration should be
- accessible to anyone. */
- atexit_fndecl
- = define_function ("atexit",
- build_function_type (void_type_node,
- pfvlist),
- /*pfn=*/0, NULL_PTR);
- mark_used (atexit_fndecl);
- atexit_node = default_conversion (atexit_fndecl);
- pop_lang_context ();
- }
-
/* Call build_cleanup before we enter the anonymous function so that
any access checks will be done relative to the current scope,
rather than the scope of the anonymous function. */
build_cleanup (decl);
/* Now start the function. */
- cleanup = start_anon_func ();
+ cleanup = start_cleanup_fn ();
/* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer
to the original function, rather than the anonymous one. That
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
finish_expr_stmt (fcall);
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
- end_anon_func ();
+ end_cleanup_fn ();
/* Call atexit with the cleanup function. */
mark_addressable (cleanup);
cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
- fcall = build_function_call (atexit_node,
- tree_cons (NULL_TREE,
- cleanup,
- NULL_TREE));
- finish_expr_stmt (fcall);
+ if (flag_use_cxa_atexit)
+ {
+ args = tree_cons (NULL_TREE, get_dso_handle_node (), NULL_TREE);
+ args = tree_cons (NULL_TREE, null_pointer_node, args);
+ args = tree_cons (NULL_TREE, cleanup, args);
+ }
+ else
+ args = tree_cons (NULL_TREE, cleanup, NULL_TREE);
+ finish_expr_stmt (build_function_call (get_atexit_node (), args));
}
void