https://gcc.gnu.org/g:b1fc2243dfd0bd87414a0e2b729b74f43ffd28cc
commit b1fc2243dfd0bd87414a0e2b729b74f43ffd28cc Author: Jakub Jelinek <ja...@redhat.com> Date: Thu Mar 20 09:06:17 2025 +0100 openmp: Fix up cloning of dynamic C++ initializers for OpenMP target [PR119370] The following testcase ICEs, because we emit the dynamic initialization twice, once for host and once for target initialization, and although we use copy_tree_body_r to unshare it, e.g. for the array initializers it can contain TARGET_EXPRs with local temporaries (or local temporaries alone). Now, these temporaries were created when current_function_decl was NULL, they are outside of any particular function, so they have DECL_CONTEXT NULL. That is normally fine, gimple_add_tmp_var will set DECL_CONTEXT for them later on to the host __static_init* function into which they are gimplified. The problem is that the copy_tree_body_r cloning happens before that (and has to, gimplification is destructive and so we couldn't gimplify the same tree again in __omp_static_init* function) and uses auto_var_in_fn_p to see what needs to be remapped. But that means it doesn't remap temporaries with NULL DECL_CONTEXT and having the same temporaries in two different functions results in ICEs (sure, one can e.g. use parent function's temporaries in a nested function). The following patch just arranges to set DECL_CONTEXT on the temporaries to the host dynamic initialization function, so that they get remapped. If gimplification cared whether DECL_CONTEXT is NULL or not, we could remember those that we've changed in a vector and undo it afterwards, but seems it doesn't really care. 2025-03-20 Jakub Jelinek <ja...@redhat.com> PR c++/119370 * decl2.cc (set_context_for_auto_vars_r): New function. (emit_partial_init_fini_fn): Call walk_tree with that function on &init before walk_tree with copy_tree_body_r. * g++.dg/gomp/pr119370.C: New test. (cherry picked from commit e0b3eeb67f6d3bfe95591d8fb0c7dfd3f1b3b4ef) Diff: --- gcc/cp/ChangeLog.omp | 8 ++++++++ gcc/cp/decl2.cc | 18 ++++++++++++++++++ gcc/testsuite/ChangeLog.omp | 6 ++++++ gcc/testsuite/g++.dg/gomp/pr119370.C | 10 ++++++++++ 4 files changed, 42 insertions(+) diff --git a/gcc/cp/ChangeLog.omp b/gcc/cp/ChangeLog.omp index 659c56a282ad..4cc1ad2df527 100644 --- a/gcc/cp/ChangeLog.omp +++ b/gcc/cp/ChangeLog.omp @@ -1,5 +1,13 @@ 2025-04-25 Thomas Schwinge <tschwi...@baylibre.com> + Backported from trunk: + 2025-03-20 Jakub Jelinek <ja...@redhat.com> + + PR c++/119370 + * decl2.cc (set_context_for_auto_vars_r): New function. + (emit_partial_init_fini_fn): Call walk_tree with that function + on &init before walk_tree with copy_tree_body_r. + Backported from trunk: 2025-02-25 Jakub Jelinek <ja...@redhat.com> diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index b1754fb8f6c2..02e1bfff979b 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -4398,6 +4398,23 @@ one_static_initialization_or_destruction (bool initp, tree decl, tree init, DECL_STATIC_FUNCTION_P (current_function_decl) = 0; } +/* Helper for emit_partial_init_fini_fn OpenMP target handling, called via + walk_tree. Set DECL_CONTEXT on any automatic temporaries which still + have it NULL to id->src_fn, so that later copy_tree_body_r can remap those. + Otherwise DECL_CONTEXT would be set only during gimplification of the host + fn and when copy_tree_body_r doesn't remap those, we'd ICE during the + target fn gimplification because the same automatic VAR_DECL can't be + used in multiple functions (with the exception of nested functions). */ + +static tree +set_context_for_auto_vars_r (tree *tp, int *, void *data) +{ + copy_body_data *id = (copy_body_data *) data; + if (auto_var_in_fn_p (*tp, NULL_TREE) && DECL_ARTIFICIAL (*tp)) + DECL_CONTEXT (*tp) = id->src_fn; + return NULL_TREE; +} + /* Generate code to do the initialization or destruction of the decls in VARS, a TREE_LIST of VAR_DECL with static storage duration. Whether initialization or destruction is performed is specified by INITP. */ @@ -4451,6 +4468,7 @@ emit_partial_init_fini_fn (bool initp, unsigned priority, tree vars, id.transform_new_cfg = true; id.transform_return_to_modify = false; id.eh_lp_nr = 0; + walk_tree (&init, set_context_for_auto_vars_r, &id, NULL); walk_tree (&init, copy_tree_body_r, &id, NULL); } /* Do one initialization or destruction. */ diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp index d13b5d1f4287..af82bfa9262f 100644 --- a/gcc/testsuite/ChangeLog.omp +++ b/gcc/testsuite/ChangeLog.omp @@ -1,5 +1,11 @@ 2025-04-25 Thomas Schwinge <tschwi...@baylibre.com> + Backported from trunk: + 2025-03-20 Jakub Jelinek <ja...@redhat.com> + + PR c++/119370 + * g++.dg/gomp/pr119370.C: New test. + Backported from trunk: 2025-02-25 Jakub Jelinek <ja...@redhat.com> diff --git a/gcc/testsuite/g++.dg/gomp/pr119370.C b/gcc/testsuite/g++.dg/gomp/pr119370.C new file mode 100644 index 000000000000..9ecc9b73db84 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/pr119370.C @@ -0,0 +1,10 @@ +// PR c++/119370 +// { dg-do compile } + +#pragma omp declare target +struct S { + int s; + S () : s (0) {} +}; +S a[2]; +#pragma omp end declare target