https://gcc.gnu.org/g:86a4af2793393e47af6b78cb7094c97914890091
commit r15-7691-g86a4af2793393e47af6b78cb7094c97914890091 Author: Jakub Jelinek <ja...@redhat.com> Date: Tue Feb 25 09:29:39 2025 +0100 openmp: Fix handling of declare target statics with array type which need destruction [PR118876] The following testcase ICEs because it attempts to emit the __tcfa function twice, once when handling the host destruction and once when handling nohost destruction. This patch fixes it by using __omp_tcfa function for the nohost case and marks it with the needed "omp declare target" and "omp declare target nohost" attributes. 2025-02-25 Jakub Jelinek <ja...@redhat.com> PR c++/118876 * cp-tree.h (register_dtor_fn): Add a bool argument defaulted to false. * decl.cc (start_cleanup_fn): Add OMP_TARGET argument, use "__omp_tcf" prefix rather than "__tcf" in that case. Add "omp declare target" and "omp declare target nohost" attributes to the fndecl. (register_dtor_fn): Add OMP_TARGET argument, pass it down to start_cleanup_fn. * decl2.cc (one_static_initialization_or_destruction): Add OMP_TARGET argument, pass it down to register_dtor_fn. (emit_partial_init_fini_fn): Pass omp_target to one_static_initialization_or_destruction. (handle_tls_init): Pass false to one_static_initialization_or_destruction. * g++.dg/gomp/pr118876.C: New test. Diff: --- gcc/cp/cp-tree.h | 2 +- gcc/cp/decl.cc | 19 ++++++++++++++----- gcc/cp/decl2.cc | 12 +++++++----- gcc/testsuite/g++.dg/gomp/pr118876.C | 6 ++++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8866d5e2c2b9..c76a92dd39be 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7201,7 +7201,7 @@ 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 tree register_dtor_fn (tree, bool = false); extern tmpl_spec_kind current_tmpl_spec_kind (int); extern tree cxx_builtin_function (tree decl); extern tree cxx_builtin_function_ext_scope (tree decl); diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 936e48e907e2..9ca8c6c44816 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -96,7 +96,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 (tree, bool); +static tree start_cleanup_fn (tree, bool, bool); static void end_cleanup_fn (void); static tree cp_make_fname_decl (location_t, tree, int); static void initialize_predefined_identifiers (void); @@ -10371,7 +10371,7 @@ get_dso_handle_node (void) is passed to the cleanup function, otherwise no argument is passed. */ static tree -start_cleanup_fn (tree decl, bool ob_parm) +start_cleanup_fn (tree decl, bool ob_parm, bool omp_target) { push_to_top_level (); @@ -10382,7 +10382,7 @@ start_cleanup_fn (tree decl, bool ob_parm) gcc_checking_assert (HAS_DECL_ASSEMBLER_NAME_P (decl)); const char *dname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); dname = targetm.strip_name_encoding (dname); - char *name = ACONCAT (("__tcf", dname, NULL)); + char *name = ACONCAT ((omp_target ? "__omp_tcf" : "__tcf", dname, NULL)); tree fntype = TREE_TYPE (ob_parm ? get_cxa_atexit_fn_ptr_type () : get_atexit_fn_ptr_type ()); @@ -10409,6 +10409,15 @@ start_cleanup_fn (tree decl, bool ob_parm) } fndecl = pushdecl (fndecl, /*hidden=*/true); + if (omp_target) + { + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("omp declare target"), NULL_TREE, + DECL_ATTRIBUTES (fndecl)); + DECL_ATTRIBUTES (fndecl) + = tree_cons (get_identifier ("omp declare target nohost"), NULL_TREE, + DECL_ATTRIBUTES (fndecl)); + } start_preparsed_function (fndecl, NULL_TREE, SF_PRE_PARSED); pop_lang_context (); @@ -10430,7 +10439,7 @@ end_cleanup_fn (void) static storage duration. */ tree -register_dtor_fn (tree decl) +register_dtor_fn (tree decl, bool omp_target) { tree cleanup; tree addr; @@ -10476,7 +10485,7 @@ register_dtor_fn (tree decl) build_cleanup (decl); /* Now start the function. */ - cleanup = start_cleanup_fn (decl, ob_parm); + cleanup = start_cleanup_fn (decl, ob_parm, omp_target); /* Now, recompute the cleanup. It may contain SAVE_EXPRs that refer to the original function, rather than the anonymous one. That diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 476e1a8abba2..fe9c56b66373 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -64,7 +64,7 @@ static tree start_partial_init_fini_fn (bool, unsigned, unsigned, bool); static void finish_partial_init_fini_fn (tree); static tree emit_partial_init_fini_fn (bool, unsigned, tree, unsigned, location_t, tree); -static void one_static_initialization_or_destruction (bool, tree, tree); +static void one_static_initialization_or_destruction (bool, tree, tree, bool); static void generate_ctor_or_dtor_function (bool, unsigned, tree, location_t, bool); static tree prune_vars_needing_no_initialization (tree *); @@ -4418,7 +4418,8 @@ fix_temporary_vars_context_r (tree *node, are destroying it. */ static void -one_static_initialization_or_destruction (bool initp, tree decl, tree init) +one_static_initialization_or_destruction (bool initp, tree decl, tree init, + bool omp_target) { /* If we are supposed to destruct and there's a trivial destructor, nothing has to be done. */ @@ -4521,7 +4522,7 @@ one_static_initialization_or_destruction (bool initp, tree decl, tree init) /* If we're using __cxa_atexit, register a function that calls the destructor for the object. */ if (flag_use_cxa_atexit) - finish_expr_stmt (register_dtor_fn (decl)); + finish_expr_stmt (register_dtor_fn (decl, omp_target)); } else finish_expr_stmt (build_cleanup (decl)); @@ -4649,7 +4650,7 @@ emit_partial_init_fini_fn (bool initp, unsigned priority, tree vars, walk_tree (&init, copy_tree_body_r, &id, NULL); } /* Do one initialization or destruction. */ - one_static_initialization_or_destruction (initp, decl, init); + one_static_initialization_or_destruction (initp, decl, init, omp_target); } decomp_finalize_var_list (sl, save_stmts_are_full_exprs_p); @@ -5204,7 +5205,8 @@ handle_tls_init (void) tree init = TREE_PURPOSE (vars); sl = decomp_handle_one_var (vars, sl, &saw_nonbase, save_stmts_are_full_exprs_p); - one_static_initialization_or_destruction (/*initp=*/true, var, init); + one_static_initialization_or_destruction (/*initp=*/true, var, init, + false); /* Output init aliases even with -fno-extern-tls-init. */ if (TARGET_SUPPORTS_ALIASES && TREE_PUBLIC (var)) diff --git a/gcc/testsuite/g++.dg/gomp/pr118876.C b/gcc/testsuite/g++.dg/gomp/pr118876.C new file mode 100644 index 000000000000..242a396bbb63 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr118876.C @@ -0,0 +1,6 @@ +// PR c++/118876 +// { dg-do compile } + +#pragma omp declare target +struct A { ~A () {} } a[2]; +#pragma omp end declare target