diff options
author | Mark Mitchell <mark@codesourcery.com> | 2007-06-01 00:44:36 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 2007-06-01 00:44:36 +0000 |
commit | 46a9e5217844297332b2e5e0c568d4448f365e96 (patch) | |
tree | 420cff63564965826ce919df9219fa10d126d563 | |
parent | fa2185f0c8be353357878e67a0bb610ab7a9a704 (diff) | |
download | gcc-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/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/decl.c | 144 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/cleanup3.C | 22 |
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; +} |