aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@codesourcery.com>2007-06-01 00:44:36 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>2007-06-01 00:44:36 +0000
commit46a9e5217844297332b2e5e0c568d4448f365e96 (patch)
tree420cff63564965826ce919df9219fa10d126d563
parentfa2185f0c8be353357878e67a0bb610ab7a9a704 (diff)
downloadgcc-46a9e5217844297332b2e5e0c568d4448f365e96.zip
gcc-46a9e5217844297332b2e5e0c568d4448f365e96.tar.gz
gcc-46a9e5217844297332b2e5e0c568d4448f365e96.tar.bz2
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
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/cp/decl.c144
-rw-r--r--gcc/cp/decl2.c5
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/init/cleanup3.C22
6 files changed, 145 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index ea352c9..ec14928 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,14 @@
+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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5e5cc9e..7afc68b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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]
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b485f1f..407e5db 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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);
}
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 9eb6fd5c..3e18c4a 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 00b365d6..51d65e7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+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
diff --git a/gcc/testsuite/g++.dg/init/cleanup3.C b/gcc/testsuite/g++.dg/init/cleanup3.C
new file mode 100644
index 0000000..da7e411
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/cleanup3.C
@@ -0,0 +1,22 @@
+// 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;
+}