https://gcc.gnu.org/g:e5d8fd9ce05611093191d500ebc39f150d0ece2b

commit r15-358-ge5d8fd9ce05611093191d500ebc39f150d0ece2b
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Fri May 10 09:21:38 2024 +0200

    c++, mingw: Fix up types of dtor hooks to 
__cxa_{,thread_}atexit/__cxa_throw on mingw ia32 [PR114968]
    
    __cxa_atexit/__cxa_thread_atexit/__cxa_throw functions accept function
    pointers to usually directly destructors rather than wrappers around
    them.
    Now, mingw ia32 uses implicitly __attribute__((thiscall)) calling
    conventions for METHOD_TYPE (where the this pointer is passed in %ecx
    register, the rest on the stack), so these functions use:
    in config/os/mingw32/os_defines.h:
     #if defined (__i386__)
     #define _GLIBCXX_CDTOR_CALLABI __thiscall
     #endif
    in libsupc++/cxxabi.h
    __cxa_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void*) 
_GLIBCXX_NOTHROW;
    __cxa_thread_atexit(void (_GLIBCXX_CDTOR_CALLABI *)(void*), void*, void *) 
_GLIBCXX_NOTHROW;
    __cxa_throw(void*, std::type_info*, void (_GLIBCXX_CDTOR_CALLABI *) (void 
*))
    __attribute__((__noreturn__));
    
    Now, mingw for some weird reason uses
     #define TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT hook_bool_void_true
    so it never actually uses __cxa_atexit, but does use __cxa_thread_atexit
    and __cxa_throw.  Recent changes for modules result in more detailed
    __cxa_*atexit/__cxa_throw prototypes precreated by the compiler, and if
    that happens and one also includes <cxxabi.h>, the compiler complains about
    mismatches in the prototypes.
    
    One thing is the missing thiscall attribute on the FUNCTION_TYPE, the
    other problem is that all of atexit/__cxa_atexit/__cxa_thread_atexit
    get function pointer types created by a single function,
    get_atexit_fn_ptr_type (), which creates it depending on if atexit
    or __cxa_atexit will be used as either void(*)(void) or void(*)(void *),
    but when using atexit and __cxa_thread_atexit it uses the wrong function
    type for __cxa_thread_atexit.
    
    The following patch adds a target hook to add the thiscall attribute to the
    function pointers, and splits the get_atexit_fn_ptr_type () function into
    get_atexit_fn_ptr_type () and get_cxa_atexit_fn_ptr_type (), the former 
always
    creates shared void(*)(void) type, the latter creates either
    void(*)(void*) (on most targets) or void(__attribute__((thiscall))*)(void*)
    (on mingw ia32).  So that we don't waiste another GTY global tree for it,
    because cleanup_type used for the same purpose for __cxa_throw should be
    the same, the code changes it to use that type too.
    
    In register_dtor_fn then based on the decision whether to use atexit,
    __cxa_atexit or __cxa_thread_atexit it picks the right function pointer
    type, and also if it decides to emit a __tcf_* wrapper for the cleanup,
    uses that type for that wrapper so that it agrees on calling convention.
    
    2024-05-10  Jakub Jelinek  <ja...@redhat.com>
    
            PR target/114968
    gcc/
            * target.def (use_atexit_for_cxa_atexit): Remove spurious space
            from comment.
            (adjust_cdtor_callabi_fntype): New cxx target hook.
            * targhooks.h (default_cxx_adjust_cdtor_callabi_fntype): Declare.
            * targhooks.cc (default_cxx_adjust_cdtor_callabi_fntype): New
            function.
            * doc/tm.texi.in (TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Add.
            * doc/tm.texi: Regenerate.
            * config/i386/i386.cc (ix86_cxx_adjust_cdtor_callabi_fntype): New
            function.
            (TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE): Redefine.
    gcc/cp/
            * cp-tree.h (atexit_fn_ptr_type_node, cleanup_type): Adjust macro
            comments.
            (get_cxa_atexit_fn_ptr_type): Declare.
            * decl.cc (get_atexit_fn_ptr_type): Adjust function comment, only
            build type for atexit argument.
            (get_cxa_atexit_fn_ptr_type): New function.
            (get_atexit_node): Call get_cxa_atexit_fn_ptr_type rather than
            get_atexit_fn_ptr_type when using __cxa_atexit.
            (get_thread_atexit_node): Call get_cxa_atexit_fn_ptr_type
            rather than get_atexit_fn_ptr_type.
            (start_cleanup_fn): Add ob_parm argument, call
            get_cxa_atexit_fn_ptr_type or get_atexit_fn_ptr_type depending
            on it and create PARM_DECL also based on that argument.
            (register_dtor_fn): Adjust start_cleanup_fn caller, use
            get_cxa_atexit_fn_ptr_type rather than get_atexit_fn_ptr_type
            for use_dtor casts.
            * except.cc (build_throw): Use get_cxa_atexit_fn_ptr_type ().

Diff:
---
 gcc/config/i386/i386.cc | 16 ++++++++++++++
 gcc/cp/cp-tree.h        |  7 +++---
 gcc/cp/decl.cc          | 59 +++++++++++++++++++++++++++----------------------
 gcc/cp/except.cc        |  6 +----
 gcc/doc/tm.texi         |  8 +++++++
 gcc/doc/tm.texi.in      |  2 ++
 gcc/target.def          | 13 ++++++++++-
 gcc/targhooks.cc        |  8 +++++++
 gcc/targhooks.h         |  1 +
 9 files changed, 85 insertions(+), 35 deletions(-)

diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 54c6c445bf14..b4838b7939e7 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25800,6 +25800,20 @@ ix86_bitint_type_info (int n, struct bitint_info *info)
   return true;
 }
 
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */
+tree
+ix86_cxx_adjust_cdtor_callabi_fntype (tree fntype)
+{
+  if (TARGET_64BIT
+      || TARGET_RTD
+      || ix86_function_type_abi (fntype) != MS_ABI)
+    return fntype;
+  /* For 32-bit MS ABI add thiscall attribute.  */
+  tree attribs = tree_cons (get_identifier ("thiscall"), NULL_TREE,
+                           TYPE_ATTRIBUTES (fntype));
+  return build_type_attribute_variant (fntype, attribs);
+}
+
 /* Implement PUSH_ROUNDING.  On 386, we have pushw instruction that
    decrements by exactly 2 no matter what the position was, there is no pushb.
 
@@ -26411,6 +26425,8 @@ static const scoped_attribute_specs *const 
ix86_attribute_table[] =
 #define TARGET_C_EXCESS_PRECISION ix86_get_excess_precision
 #undef TARGET_C_BITINT_TYPE_INFO
 #define TARGET_C_BITINT_TYPE_INFO ix86_bitint_type_info
+#undef TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE
+#define TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE 
ix86_cxx_adjust_cdtor_callabi_fntype
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 #undef TARGET_PUSH_ARGUMENT
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index db098c32f2d0..07e9632942bb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -368,8 +368,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define throw_fn                       cp_global_trees[CPTI_THROW_FN]
 #define rethrow_fn                     cp_global_trees[CPTI_RETHROW_FN]
 
-/* The type of the function-pointer argument to "__cxa_atexit" (or
-   "std::atexit", if "__cxa_atexit" is not being used).  */
+/* The type of the function-pointer argument to "std::atexit".  */
 #define atexit_fn_ptr_type_node         
cp_global_trees[CPTI_ATEXIT_FN_PTR_TYPE]
 
 /* A pointer to `std::atexit'.  */
@@ -384,7 +383,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 /* The declaration of the dynamic_cast runtime.  */
 #define dynamic_cast_node              cp_global_trees[CPTI_DCAST]
 
-/* The type of a destructor.  */
+/* The type of a destructor, passed to __cxa_atexit, __cxa_thread_atexit
+   or __cxa_throw.  */
 #define cleanup_type                   cp_global_trees[CPTI_CLEANUP_TYPE]
 
 /* The type of the vtt parameter passed to subobject constructors and
@@ -7067,6 +7067,7 @@ extern tree check_default_argument                (tree, 
tree, tsubst_flags_t);
 extern int wrapup_namespace_globals            ();
 extern tree create_implicit_typedef            (tree, tree);
 extern int local_variable_p                    (const_tree);
+extern tree get_cxa_atexit_fn_ptr_type         ();
 extern tree register_dtor_fn                   (tree);
 extern tmpl_spec_kind current_tmpl_spec_kind   (int);
 extern tree cxx_builtin_function               (tree decl);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index e02562466a74..3fc8835154d9 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -93,7 +93,7 @@ static void record_key_method_defined (tree);
 static tree create_array_type_for_decl (tree, tree, tree, location_t);
 static tree get_atexit_node (void);
 static tree get_dso_handle_node (void);
-static tree start_cleanup_fn (void);
+static tree start_cleanup_fn (bool);
 static void end_cleanup_fn (void);
 static tree cp_make_fname_decl (location_t, tree, int);
 static void initialize_predefined_identifiers (void);
@@ -9678,34 +9678,39 @@ 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
+/* Returns the type for the argument to "atexit" corresponding to the function
    to be called when the program exits.  */
 
 static tree
-get_atexit_fn_ptr_type (void)
+get_atexit_fn_ptr_type ()
 {
-  tree fn_type;
-
   if (!atexit_fn_ptr_type_node)
     {
-      tree arg_type;
-      if (flag_use_cxa_atexit 
-         && !targetm.cxx.use_atexit_for_cxa_atexit ())
-       /* The parameter to "__cxa_atexit" is "void (*)(void *)".  */
-       arg_type = ptr_type_node;
-      else
-       /* The parameter to "atexit" is "void (*)(void)".  */
-       arg_type = NULL_TREE;
-      
-      fn_type = build_function_type_list (void_type_node,
-                                         arg_type, NULL_TREE);
+      tree fn_type = build_function_type_list (void_type_node, NULL_TREE);
       atexit_fn_ptr_type_node = build_pointer_type (fn_type);
     }
 
   return atexit_fn_ptr_type_node;
 }
 
+/* Returns the type for the argument to "__cxa_atexit", "__cxa_thread_atexit"
+   or "__cxa_throw" corresponding to the destructor to be called when the
+   program exits.  */
+
+tree
+get_cxa_atexit_fn_ptr_type ()
+{
+  if (!cleanup_type)
+    {
+      tree fntype = build_function_type_list (void_type_node,
+                                             ptr_type_node, NULL_TREE);
+      fntype = targetm.cxx.adjust_cdtor_callabi_fntype (fntype);
+      cleanup_type = build_pointer_type (fntype);
+    }
+
+  return cleanup_type;
+}
+
 /* 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.  */
@@ -9736,7 +9741,7 @@ get_atexit_node (void)
       use_aeabi_atexit = targetm.cxx.use_aeabi_atexit ();
       /* First, build the pointer-to-function type for the first
         argument.  */
-      fn_ptr_type = get_atexit_fn_ptr_type ();
+      fn_ptr_type = get_cxa_atexit_fn_ptr_type ();
       /* Then, build the rest of the argument types.  */
       argtype2 = ptr_type_node;
       if (use_aeabi_atexit)
@@ -9819,7 +9824,7 @@ get_thread_atexit_node (void)
 
      int __cxa_thread_atexit (void (*)(void *), void *, void *) */
   tree fn_type = build_function_type_list (integer_type_node,
-                                          get_atexit_fn_ptr_type (),
+                                          get_cxa_atexit_fn_ptr_type (),
                                           ptr_type_node, ptr_type_node,
                                           NULL_TREE);
 
@@ -9861,12 +9866,13 @@ get_dso_handle_node (void)
 }
 
 /* Begin a new function with internal linkage whose job will be simply
-   to destroy some particular variable.  */
+   to destroy some particular variable.  OB_PARM is true if object pointer
+   is passed to the cleanup function, otherwise no argument is passed.  */
 
 static GTY(()) int start_cleanup_cnt;
 
 static tree
-start_cleanup_fn (void)
+start_cleanup_fn (bool ob_parm)
 {
   char name[32];
 
@@ -9877,8 +9883,9 @@ start_cleanup_fn (void)
 
   /* Build the name of the function.  */
   sprintf (name, "__tcf_%d", start_cleanup_cnt++);
+  tree fntype = TREE_TYPE (ob_parm ? get_cxa_atexit_fn_ptr_type ()
+                                  : get_atexit_fn_ptr_type ());
   /* Build the function declaration.  */
-  tree fntype = TREE_TYPE (get_atexit_fn_ptr_type ());
   tree fndecl = build_lang_decl (FUNCTION_DECL, get_identifier (name), fntype);
   DECL_CONTEXT (fndecl) = FROB_CONTEXT (current_namespace);
   /* It's a function with internal linkage, generated by the
@@ -9891,7 +9898,7 @@ start_cleanup_fn (void)
      emissions this way.  */
   DECL_DECLARED_INLINE_P (fndecl) = 1;
   DECL_INTERFACE_KNOWN (fndecl) = 1;
-  if (flag_use_cxa_atexit && !targetm.cxx.use_atexit_for_cxa_atexit ())
+  if (ob_parm)
     {
       /* Build the parameter.  */
       tree parmdecl = cp_build_parm_decl (fndecl, NULL_TREE, ptr_type_node);
@@ -9968,8 +9975,8 @@ register_dtor_fn (tree decl)
       build_cleanup (decl);
   
       /* Now start the function.  */
-      cleanup = start_cleanup_fn ();
-      
+      cleanup = start_cleanup_fn (ob_parm);
+
       /* 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,
@@ -9998,7 +10005,7 @@ register_dtor_fn (tree decl)
     {
       /* We must convert CLEANUP to the type that "__cxa_atexit"
         expects.  */
-      cleanup = build_nop (get_atexit_fn_ptr_type (), cleanup);
+      cleanup = build_nop (get_cxa_atexit_fn_ptr_type (), cleanup);
       /* "__cxa_atexit" will pass the address of DECL to the
         cleanup function.  */
       mark_used (decl);
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index f1ffda22fd32..1eb3ba53b4b5 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -645,11 +645,7 @@ build_throw (location_t loc, tree exp, tsubst_flags_t 
complain)
 
       /* The CLEANUP_TYPE is the internal type of a destructor.  */
       if (!cleanup_type)
-       {
-         tree tmp = build_function_type_list (void_type_node,
-                                              ptr_type_node, NULL_TREE);
-         cleanup_type = build_pointer_type (tmp);
-       }
+       cleanup_type = get_cxa_atexit_fn_ptr_type ();
 
       if (!throw_fn)
        {
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index c8b8b126b242..cd50078227d9 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -11117,6 +11117,14 @@ shared libraries are run in the correct order when the 
libraries are
 unloaded. The default is to return false.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE (tree 
@var{fntype})
+This hook returns a possibly modified @code{FUNCTION_TYPE} for arguments
+to @code{__cxa_atexit}, @code{__cxa_thread_atexit} or @code{__cxa_throw}
+function pointers.  ABIs like mingw32 require special attributes to be added
+to function types pointed to by arguments of these functions.
+The default is to return the passed argument unmodified.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_CXX_ADJUST_CLASS_AT_DEFINITION (tree 
@var{type})
 @var{type} is a C++ class (i.e., RECORD_TYPE or UNION_TYPE) that has just
 been defined.  Use this hook to make adjustments to the class (eg, tweak
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 658e1e63371e..058bd56487a9 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7223,6 +7223,8 @@ floating-point support; they are not included in this 
mechanism.
 
 @hook TARGET_CXX_USE_ATEXIT_FOR_CXA_ATEXIT
 
+@hook TARGET_CXX_ADJUST_CDTOR_CALLABI_FNTYPE
+
 @hook TARGET_CXX_ADJUST_CLASS_AT_DEFINITION
 
 @hook TARGET_CXX_DECL_MANGLING_CONTEXT
diff --git a/gcc/target.def b/gcc/target.def
index fdad7bbc93e2..c27df8095be1 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6498,7 +6498,7 @@ is in effect.  The default is to return false to use 
@code{__cxa_atexit}.",
  hook_bool_void_false)
 
 /* Returns true if target may use atexit in the same manner as
-   __cxa_atexit  to register static destructors.  */
+   __cxa_atexit to register static destructors.  */
 DEFHOOK
 (use_atexit_for_cxa_atexit,
  "This hook returns true if the target @code{atexit} function can be used\n\
@@ -6509,6 +6509,17 @@ unloaded. The default is to return false.",
  bool, (void),
  hook_bool_void_false)
 
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */
+DEFHOOK
+(adjust_cdtor_callabi_fntype,
+ "This hook returns a possibly modified @code{FUNCTION_TYPE} for arguments\n\
+to @code{__cxa_atexit}, @code{__cxa_thread_atexit} or @code{__cxa_throw}\n\
+function pointers.  ABIs like mingw32 require special attributes to be added\n\
+to function types pointed to by arguments of these functions.\n\
+The default is to return the passed argument unmodified.",
+ tree, (tree fntype),
+ default_cxx_adjust_cdtor_callabi_fntype)
+
 DEFHOOK
 (adjust_class_at_definition,
 "@var{type} is a C++ class (i.e., RECORD_TYPE or UNION_TYPE) that has just\n\
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 8c84deea97d3..fb339bf75dd8 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -329,6 +329,14 @@ default_cxx_get_cookie_size (tree type)
   return cookie_size;
 }
 
+/* Returns modified FUNCTION_TYPE for cdtor callabi.  */
+
+tree
+default_cxx_adjust_cdtor_callabi_fntype (tree fntype)
+{
+  return fntype;
+}
+
 /* Return true if a parameter must be passed by reference.  This version
    of the TARGET_PASS_BY_REFERENCE hook uses just MUST_PASS_IN_STACK.  */
 
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index ca289f30eda6..85f3817c176e 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -65,6 +65,7 @@ extern machine_mode default_mode_for_suffix (char);
 
 extern tree default_cxx_guard_type (void);
 extern tree default_cxx_get_cookie_size (tree);
+extern tree default_cxx_adjust_cdtor_callabi_fntype (tree);
 
 extern bool hook_pass_by_reference_must_pass_in_stack
   (cumulative_args_t, const function_arg_info &);

Reply via email to