Commit 46a9e521 by Mark Mitchell Committed by Mark Mitchell

decl.c (get_atexit_fn_ptr_type): New function.

	* decl.c (get_atexit_fn_ptr_type): New function.
	(get_atexit_node): Use it.
	(start_cleanup_fn): Likewise.
	(register_dtor_fn): Use the object's destructor, instead of a
	separate cleanup function, where possible.
	* cp-tree.h (CPTI_ATEXIT_FN_PTR_TYPE): New enumerator.
	(atexit_fn_ptr_type_node): New macro.
	* decl2.c (build_cleanup): Use build_address.
	* g++.dg/init/cleanup3.C: New test.

From-SVN: r125253
parent fa2185f0
2007-05-31 Mark Mitchell <mark@codesourcery.com>
* decl.c (get_atexit_fn_ptr_type): New function.
(get_atexit_node): Use it.
(start_cleanup_fn): Likewise.
(register_dtor_fn): Use the object's destructor, instead of a
separate cleanup function, where possible.
* cp-tree.h (CPTI_ATEXIT_FN_PTR_TYPE): New enumerator.
(atexit_fn_ptr_type_node): New macro.
* decl2.c (build_cleanup): Use build_address.
2007-05-31 Daniel Berlin <dberlin@dberlin.org>
* typeck.c (build_binary_op): Include types in error.
......
......@@ -615,6 +615,7 @@ enum cp_tree_index
CPTI_JCLASS,
CPTI_TERMINATE,
CPTI_CALL_UNEXPECTED,
CPTI_ATEXIT_FN_PTR_TYPE,
CPTI_ATEXIT,
CPTI_DSO_HANDLE,
CPTI_DCAST,
......@@ -704,6 +705,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
/* The declaration for "__cxa_call_unexpected". */
#define call_unexpected_node cp_global_trees[CPTI_CALL_UNEXPECTED]
/* The type of the function-pointer argument to "__cxa_atexit" (or
"std::atexit", if "__cxa_atexit" is not being used). */
#define atexit_fn_ptr_type_node cp_global_trees[CPTI_ATEXIT_FN_PTR_TYPE]
/* A pointer to `std::atexit'. */
#define atexit_node cp_global_trees[CPTI_ATEXIT]
......
......@@ -5424,6 +5424,33 @@ declare_global_var (tree name, tree type)
return decl;
}
/* Returns the type for the argument to "__cxa_atexit" (or "atexit",
if "__cxa_atexit" is not being used) corresponding to the function
to be called when the program exits. */
static tree
get_atexit_fn_ptr_type (void)
{
tree arg_types;
tree fn_type;
if (!atexit_fn_ptr_type_node)
{
if (flag_use_cxa_atexit
&& !targetm.cxx.use_atexit_for_cxa_atexit ())
/* The parameter to "__cxa_atexit" is "void (*)(void *)". */
arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
else
/* The parameter to "atexit" is "void (*)(void)". */
arg_types = void_list_node;
fn_type = build_function_type (void_type_node, arg_types);
atexit_fn_ptr_type_node = build_pointer_type (fn_type);
}
return atexit_fn_ptr_type_node;
}
/* Returns a pointer to the `atexit' function. Note that if
FLAG_USE_CXA_ATEXIT is nonzero, then this will actually be the new
`__cxa_atexit' function specified in the IA64 C++ ABI. */
......@@ -5453,9 +5480,7 @@ get_atexit_node (void)
use_aeabi_atexit = targetm.cxx.use_aeabi_atexit ();
/* 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);
fn_ptr_type = get_atexit_fn_ptr_type ();
/* Then, build the rest of the argument types. */
arg_types = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
if (use_aeabi_atexit)
......@@ -5484,8 +5509,7 @@ get_atexit_node (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);
fn_ptr_type = get_atexit_fn_ptr_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);
......@@ -5526,7 +5550,6 @@ static tree
start_cleanup_fn (void)
{
char name[32];
tree parmtypes;
tree fntype;
tree fndecl;
bool use_cxa_atexit = flag_use_cxa_atexit
......@@ -5537,19 +5560,10 @@ start_cleanup_fn (void)
/* No need to mangle this. */
push_lang_context (lang_name_c);
/* 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 (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", start_cleanup_cnt++);
/* Build the function declaration. */
fntype = TREE_TYPE (get_atexit_fn_ptr_type ());
fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
/* It's a function with internal linkage, generated by the
compiler. */
......@@ -5601,50 +5615,96 @@ register_dtor_fn (tree decl)
tree compound_stmt;
tree args;
tree fcall;
tree type;
bool use_dtor;
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
type = TREE_TYPE (decl);
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return void_zero_node;
/* 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_cleanup_fn ();
/* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer
to the original function, rather than the anonymous one. That
will make the back end think that nested functions are in use,
which causes confusion. */
push_deferring_access_checks (dk_no_check);
fcall = build_cleanup (decl);
pop_deferring_access_checks ();
/* If we're using "__cxa_atexit" (or "__aeabi_atexit"), and DECL is
a class object, we can just pass the destructor to
"__cxa_atexit"; we don't have to build a temporary function to do
the cleanup. */
use_dtor = (flag_use_cxa_atexit
&& !targetm.cxx.use_atexit_for_cxa_atexit ()
&& CLASS_TYPE_P (type));
if (use_dtor)
{
int idx;
/* Create the body of the anonymous function. */
compound_stmt = begin_compound_stmt (BCS_FN_BODY);
finish_expr_stmt (fcall);
finish_compound_stmt (compound_stmt);
end_cleanup_fn ();
/* Find the destructor. */
idx = lookup_fnfields_1 (type, complete_dtor_identifier);
gcc_assert (idx >= 0);
cleanup = VEC_index (tree, CLASSTYPE_METHOD_VEC (type), idx);
/* Make sure it is accessible. */
perform_or_defer_access_check (TYPE_BINFO (type), cleanup, cleanup);
}
else
{
/* 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_cleanup_fn ();
/* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer
to the original function, rather than the anonymous one. That
will make the back end think that nested functions are in use,
which causes confusion. */
push_deferring_access_checks (dk_no_check);
fcall = build_cleanup (decl);
pop_deferring_access_checks ();
/* Create the body of the anonymous function. */
compound_stmt = begin_compound_stmt (BCS_FN_BODY);
finish_expr_stmt (fcall);
finish_compound_stmt (compound_stmt);
end_cleanup_fn ();
}
/* Call atexit with the cleanup function. */
cxx_mark_addressable (cleanup);
mark_used (cleanup);
cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
cleanup = build_address (cleanup);
if (flag_use_cxa_atexit && !targetm.cxx.use_atexit_for_cxa_atexit ())
{
tree addr;
if (use_dtor)
{
/* We must convert CLEANUP to the type that "__cxa_atexit"
expects. */
cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup);
/* "__cxa_atexit" will pass the address of DECL to the
cleanup function. */
mark_used (decl);
addr = build_address (decl);
/* The declared type of the parameter to "__cxa_atexit" is
"void *". For plain "T*", we could just let the
machinery in build_function_call convert it -- but if the
type is "cv-qualified T *", then we need to convert it
before passing it in, to avoid spurious errors. */
addr = build_nop (ptr_type_node, addr);
}
else
/* Since the cleanup functions we build ignore the address
they're given, there's no reason to pass the actual address
in, and, in general, it's cheaper to pass NULL than any
other value. */
addr = null_pointer_node;
args = tree_cons (NULL_TREE,
build_unary_op (ADDR_EXPR, get_dso_handle_node (), 0),
NULL_TREE);
if (targetm.cxx.use_aeabi_atexit ())
{
args = tree_cons (NULL_TREE, cleanup, args);
args = tree_cons (NULL_TREE, null_pointer_node, args);
args = tree_cons (NULL_TREE, addr, args);
}
else
{
args = tree_cons (NULL_TREE, null_pointer_node, args);
args = tree_cons (NULL_TREE, addr, args);
args = tree_cons (NULL_TREE, cleanup, args);
}
}
......
......@@ -2190,10 +2190,7 @@ build_cleanup (tree decl)
if (TREE_CODE (type) == ARRAY_TYPE)
temp = decl;
else
{
cxx_mark_addressable (decl);
temp = build1 (ADDR_EXPR, build_pointer_type (type), decl);
}
temp = build_address (decl);
temp = build_delete (TREE_TYPE (temp), temp,
sfk_complete_destructor,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
......
2007-05-31 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/cleanup3.C: New test.
2007-05-31 Rask Ingemann Lambertsen <rask@sygehus.dk>
* gcc.c-torture/compile/limits-caselabels.c: Fix for targets where
// Check that on targets with "__cxa_atexit" we use destructors,
// rather than cleanup functions, to destroy objects with static
// storage duration.
// { dg-require-effective-target "cxa_atexit" }
// Cleanup functions generated by G++ have the "_tcf" prefix.
// { dg-final { scan-assembler-not "_tcf" } }
struct S {
~S();
};
struct T {
S s;
};
S s;
T t;
void f() {
static S s;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment