Hi! 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. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 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. --- gcc/cp/cp-tree.h.jj 2025-02-24 00:06:25.657734149 +0100 +++ gcc/cp/cp-tree.h 2025-02-24 15:39:04.741553394 +0100 @@ -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); --- gcc/cp/decl.cc.jj 2025-02-24 15:08:52.027729921 +0100 +++ gcc/cp/decl.cc 2025-02-24 16:26:55.512032855 +0100 @@ -96,7 +96,7 @@ static void record_key_method_defined (t 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_par 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_par } 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 --- gcc/cp/decl2.cc.jj 2025-02-24 00:06:25.668733997 +0100 +++ gcc/cp/decl2.cc 2025-02-24 15:38:24.414115664 +0100 @@ -64,7 +64,7 @@ static tree start_partial_init_fini_fn ( 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 /* 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, u 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)) --- gcc/testsuite/g++.dg/gomp/pr118876.C.jj 2025-02-24 16:29:28.234034898 +0100 +++ gcc/testsuite/g++.dg/gomp/pr118876.C 2025-02-24 16:28:58.973417698 +0100 @@ -0,0 +1,6 @@ +// PR c++/118876 +// { dg-do compile } + +#pragma omp declare target +struct A { ~A () {} } a[2]; +#pragma omp end declare target Jakub