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.

Reply via email to