https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127559
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I'd say the bug is in
if (TREE_TYPE (t) && LAMBDA_TYPE_P (TREE_TYPE (t)))
being done on any expression (and it already rules out TARGET_EXPR from those).
It should be done only for VAR_DECL/PARM_DECL/RESULT_DECL, those are something
that can be mapped, not arbitrary expressions.
void
foo (int *a)
{
#pragma omp target map (to: a[0])
{
auto b = [=] { return *a; };
auto c = [=] { return b (); };
if (c () != 42)
__builtin_abort ();
}
}
int
main ()
{
int a = 42;
foo (&a);
}
could be better testcase that can be actually run.
First fix I have is something like
--- a/gcc/cp/semantics.cc 2026-10-13 22:48:00.327522386 +0200
+++ b/gcc/cp/semantics.cc 2026-10-15 17:47:12.964415476 +0200
@@ -11273,25 +11273,30 @@ finish_omp_target_clauses_r (tree *tp, i
{
if (tree block = BIND_EXPR_BLOCK (t))
for (tree var = BLOCK_VARS (block); var; var = DECL_CHAIN (var))
- if (!data->local_decls.contains (var))
+ if ((VAR_P (var)
+ || TREE_CODE (var) == PARM_DECL
+ || TREE_CODE (var) == RESULT_DECL)
+ && !data->local_decls.contains (var))
data->local_decls.add (var);
return NULL_TREE;
}
- if (TREE_TYPE (t) && LAMBDA_TYPE_P (TREE_TYPE (t)))
- {
- tree lt = TREE_TYPE (t);
- gcc_assert (CLASS_TYPE_P (lt));
+ if (tree lt = TREE_TYPE (t))
+ if (LAMBDA_TYPE_P (lt))
+ {
+ gcc_assert (CLASS_TYPE_P (lt));
- if (!data->lambda_objects_accessed.contains (t)
- /* Do not prepare to create target maps for locally declared
- lambdas or anonymous ones. */
- && !data->local_decls.contains (t)
- && TREE_CODE (t) != TARGET_EXPR)
- data->lambda_objects_accessed.add (t);
- *walk_subtrees = 0;
- return NULL_TREE;
- }
+ if ((VAR_P (t)
+ || TREE_CODE (t) == PARM_DECL
+ || TREE_CODE (t) == RESULT_DECL)
+ && !data->lambda_objects_accessed.contains (t)
+ /* Do not prepare to create target maps for locally declared
+ lambdas or anonymous ones. */
+ && !data->local_decls.contains (t))
+ data->lambda_objects_accessed.add (t);
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
return NULL_TREE;
}
But I'm not sure this is correct.
One thing is that e.g
template <typename T>
void
foo (T x) {}
void
bar (float *a)
{
auto b = [=] { a; };
#pragma omp target
foo (b);
}
results in foo<bar(float*)::<lambda()> > (TARGET_EXPR <D.3212, b>), so I'm not
convinced one can/should skip walking subtrees of TARGET_EXPRs, because then
we'll miss the use in TARGET_EXPR_INITIAL.
Maybe we should instead add to data->local_decls TARGET_EXPR_SLOT when we see a
TARGET_EXPR? I'd hope we don't use TARGET_EXPRs from outside of a target
region inside of it...
Unsure if we can have valid structures containing lambda closures among
non-static data members except in lambda closures themselves.
Though maybe for that we record those as well.