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 <jakub@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)
2025-04-25 Thomas Schwinge <tschwinge@baylibre.com>
+ Backported from trunk:
+ 2025-03-20 Jakub Jelinek <jakub@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 <jakub@redhat.com>
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. */
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. */
2025-04-25 Thomas Schwinge <tschwinge@baylibre.com>
+ Backported from trunk:
+ 2025-03-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/119370
+ * g++.dg/gomp/pr119370.C: New test.
+
Backported from trunk:
2025-02-25 Jakub Jelinek <jakub@redhat.com>
--- /dev/null
+// 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