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 <jakub@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.
(cherry picked from commit
86a4af2793393e47af6b78cb7094c97914890091)
2025-04-25 Thomas Schwinge <tschwinge@baylibre.com>
+ Backported from trunk:
+ 2025-02-25 Jakub Jelinek <jakub@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.
+
Backported from trunk:
2024-08-07 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tobias@baylibre.com>
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);
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 (bool);
+static tree start_cleanup_fn (bool, bool);
static void end_cleanup_fn (void);
static tree cp_make_fname_decl (location_t, tree, int);
static void initialize_predefined_identifiers (void);
static GTY(()) int start_cleanup_cnt;
static tree
-start_cleanup_fn (bool ob_parm)
+start_cleanup_fn (bool ob_parm, bool omp_target)
{
char name[32];
push_lang_context (lang_name_c);
/* Build the name of the function. */
- sprintf (name, "__tcf_%d", start_cleanup_cnt++);
+ sprintf (name, "%s_%d",
+ (omp_target ? "__omp_tcf" : "__tcf"), start_cleanup_cnt++);
tree fntype = TREE_TYPE (ob_parm ? get_cxa_atexit_fn_ptr_type ()
: get_atexit_fn_ptr_type ());
/* Build the function declaration. */
}
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 ();
static storage duration. */
tree
-register_dtor_fn (tree decl)
+register_dtor_fn (tree decl, bool omp_target)
{
tree cleanup;
tree addr;
build_cleanup (decl);
/* Now start the function. */
- cleanup = start_cleanup_fn (ob_parm);
+ cleanup = start_cleanup_fn (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
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 *);
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. */
/* 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));
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);
}
if (omp_target)
{
tree var = TREE_VALUE (vars);
tree init = TREE_PURPOSE (vars);
- 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))
+2025-04-25 Thomas Schwinge <tschwinge@baylibre.com>
+
+ Backported from trunk:
+ 2025-02-25 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/118876
+ * g++.dg/gomp/pr118876.C: New test.
+
2025-04-17 Kwok Cheung Yeung <kcyeung@baylibre.com>
* c-c++-common/gomp/target-map-iterators-3.c: Update expected Gimple
--- /dev/null
+// PR c++/118876
+// { dg-do compile }
+
+#pragma omp declare target
+struct A { ~A () {} } a[2];
+#pragma omp end declare target