* decl.c (get_atexit_fn_ptr_type): New function.
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Jun 2007 00:44:36 +0000 (00:44 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 1 Jun 2007 00:44:36 +0000 (00:44 +0000)
(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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@125253 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/cleanup3.C [new file with mode: 0644]

index ea352c9..ec14928 100644 (file)
@@ -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.
index 5e5cc9e..7afc68b 100644 (file)
@@ -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]
 
index b485f1f..407e5db 100644 (file)
@@ -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);
        }
     }
index 9eb6fd5..3e18c4a 100644 (file)
@@ -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);
index 00b365d..51d65e7 100644 (file)
@@ -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 (file)
index 0000000..da7e411
--- /dev/null
@@ -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;
+}