diff options
author | Jakub Jelinek <jakub@redhat.com> | 2024-05-10 09:21:38 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2024-05-10 09:21:38 +0200 |
commit | e5d8fd9ce05611093191d500ebc39f150d0ece2b (patch) | |
tree | 91201a10cc484f86c82b8a3af66d982f4ba4bc51 /gcc/cp | |
parent | ac255c7afeb8a558bd6224ff77277eebcd849d6e (diff) | |
download | gcc-e5d8fd9ce05611093191d500ebc39f150d0ece2b.zip gcc-e5d8fd9ce05611093191d500ebc39f150d0ece2b.tar.gz gcc-e5d8fd9ce05611093191d500ebc39f150d0ece2b.tar.bz2 |
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 <jakub@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 ().
Diffstat (limited to 'gcc/cp')
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/decl.cc | 59 | ||||
-rw-r--r-- | gcc/cp/except.cc | 6 |
3 files changed, 38 insertions, 34 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index db098c3..07e9632 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 e025624..3fc8835 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 f1ffda22..1eb3ba5 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) { |