https://gcc.gnu.org/g:ca716a50c92294ae8597925b12fbfbbc06dc93cc

commit ca716a50c92294ae8597925b12fbfbbc06dc93cc
Author: Tobias Burnus <tbur...@baylibre.com>
Date:   Thu Jan 23 22:26:57 2025 +0100

    Fortran: Add OpenMP 'interop' directive parsing support
    
    Parse OpenMP's 'interop' directive but stop with a 'sorry, unimplemented'
    after resolving.
    
    Additionally, it moves some clause dumping away from the end directive as
    that lead to 'nowait' not being printed when it should as some cases were
    missed.
    
    gcc/fortran/ChangeLog:
    
            * dump-parse-tree.cc (show_omp_namelist): Handle OMP_LIST_INIT.
            (show_omp_clauses): Handle OMP_LIST_{INIT,USE,DESTORY}; move 
'nowait'
            from end-directive to the directive dump.
            (show_omp_node, show_code_node): Handle EXEC_OMP_INTEROP.
            * gfortran.h (enum gfc_statement): Add ST_OMP_INTEROP.
            (OMP_LIST_INIT, OMP_LIST_USE, OMP_LIST_DESTROY): Add.
            (enum gfc_exec_op): Add EXEC_OMP_INTEROP.
            (struct gfc_omp_namelist): Add interop items to union.
            (gfc_free_omp_namelist): Add boolean arg.
            * match.cc (gfc_free_omp_namelist): Update to free
            interop union members.
            * match.h (gfc_match_omp_interop): New.
            * openmp.cc (gfc_omp_directives): Uncomment 'interop' entry.
            (gfc_free_omp_clauses, gfc_match_omp_allocate,
            gfc_match_omp_flush, gfc_match_omp_clause_reduction): Update
            call.
            (enum omp_mask2): Add OMP_CLAUSE_{INIT,USE,DESTROY}.
            (OMP_INTEROP_CLAUSES): Use it.
            (gfc_match_omp_clauses): Match those clauses.
            (gfc_match_omp_prefer_type, gfc_match_omp_init,
            gfc_match_omp_interop): New.
            (resolve_omp_clauses): Handle interop clauses.
            (omp_code_to_statement): Add ST_OMP_INTEROP.
            (gfc_resolve_omp_directive): Add EXEC_OMP_INTEROP.
            * parse.cc (decode_omp_directive): Parse 'interop' directive.
            (next_statement, gfc_ascii_statement): Handle ST_OMP_INTEROP.
            * st.cc (gfc_free_statement): Likewise
            * resolve.cc (gfc_resolve_code): Handle EXEC_OMP_INTEROP.
            * trans.cc (trans_code): Likewise.
            * trans-openmp.cc (gfc_trans_omp_directive): Print 'sorry'
            for EXEC_OMP_INTEROP.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/gomp/interop-1.f90: New test.
            * gfortran.dg/gomp/interop-2.f90: New test.
            * gfortran.dg/gomp/interop-3.f90: New test.
    
    (cherry picked from commit 4ce9e0a579fcd216c1a3439525201473402a895d)

Diff:
---
 gcc/fortran/ChangeLog.omp                    |  37 +++
 gcc/fortran/dump-parse-tree.cc               |  61 +++--
 gcc/fortran/gfortran.h                       |  15 +-
 gcc/fortran/match.cc                         |  12 +
 gcc/fortran/match.h                          |   1 +
 gcc/fortran/openmp.cc                        | 383 ++++++++++++++++++++++++++-
 gcc/fortran/parse.cc                         |   7 +
 gcc/fortran/resolve.cc                       |   1 +
 gcc/fortran/st.cc                            |   1 +
 gcc/fortran/trans-openmp.cc                  |   3 +
 gcc/fortran/trans.cc                         |   3 +-
 gcc/testsuite/ChangeLog.omp                  |   9 +
 gcc/testsuite/gfortran.dg/gomp/interop-1.f90 |  62 +++++
 gcc/testsuite/gfortran.dg/gomp/interop-2.f90 |  46 ++++
 gcc/testsuite/gfortran.dg/gomp/interop-3.f90 |  59 +++++
 libgomp/ChangeLog                            |  36 ---
 libgomp/ChangeLog.omp                        |  36 +++
 17 files changed, 716 insertions(+), 56 deletions(-)

diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 31470f4852e4..051b90a6a7d7 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,40 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-06  Tobias Burnus  <tbur...@baylibre.com>
+
+       * dump-parse-tree.cc (show_omp_namelist): Handle OMP_LIST_INIT.
+       (show_omp_clauses): Handle OMP_LIST_{INIT,USE,DESTORY}; move 'nowait'
+       from end-directive to the directive dump.
+       (show_omp_node, show_code_node): Handle EXEC_OMP_INTEROP.
+       * gfortran.h (enum gfc_statement): Add ST_OMP_INTEROP.
+       (OMP_LIST_INIT, OMP_LIST_USE, OMP_LIST_DESTROY): Add.
+       (enum gfc_exec_op): Add EXEC_OMP_INTEROP.
+       (struct gfc_omp_namelist): Add interop items to union.
+       (gfc_free_omp_namelist): Add boolean arg.
+       * match.cc (gfc_free_omp_namelist): Update to free
+       interop union members.
+       * match.h (gfc_match_omp_interop): New.
+       * openmp.cc (gfc_omp_directives): Uncomment 'interop' entry.
+       (gfc_free_omp_clauses, gfc_match_omp_allocate,
+       gfc_match_omp_flush, gfc_match_omp_clause_reduction): Update
+       call.
+       (enum omp_mask2): Add OMP_CLAUSE_{INIT,USE,DESTROY}.
+       (OMP_INTEROP_CLAUSES): Use it.
+       (gfc_match_omp_clauses): Match those clauses.
+       (gfc_match_omp_prefer_type, gfc_match_omp_init,
+       gfc_match_omp_interop): New.
+       (resolve_omp_clauses): Handle interop clauses.
+       (omp_code_to_statement): Add ST_OMP_INTEROP.
+       (gfc_resolve_omp_directive): Add EXEC_OMP_INTEROP.
+       * parse.cc (decode_omp_directive): Parse 'interop' directive.
+       (next_statement, gfc_ascii_statement): Handle ST_OMP_INTEROP.
+       * st.cc (gfc_free_statement): Likewise
+       * resolve.cc (gfc_resolve_code): Handle EXEC_OMP_INTEROP.
+       * trans.cc (trans_code): Likewise.
+       * trans-openmp.cc (gfc_trans_omp_directive): Print 'sorry'
+       for EXEC_OMP_INTEROP.
+
 2024-07-29  Tobias Burnus  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 28e5b48dad0f..595f9c3c7c12 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1376,6 +1376,8 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
            }
          ns_iter = n->u2.ns;
        }
+      else if (list_type == OMP_LIST_INIT && n != n2)
+       fputs (") INIT(", dumpfile);
       if (list_type == OMP_LIST_ALLOCATE)
        {
          if (n->u2.allocator)
@@ -1529,6 +1531,39 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
            fputs (", ", dumpfile);
          continue;
        }
+      else if (list_type == OMP_LIST_INIT)
+       {
+         int i = 0;
+         if (n->u.init.target)
+           fputs ("target,", dumpfile);
+         if (n->u.init.targetsync)
+           fputs ("targetsync,", dumpfile);
+         char *prefer_type = n->u.init.str;
+         if (n->u.init.len)
+           fputs ("prefer_type(", dumpfile);
+         if (n->u.init.len)
+           while (*prefer_type)
+             {
+               fputc ('{', dumpfile);
+               if (n->u2.interop_int && n->u2.interop_int[i] != 0)
+                 fprintf (dumpfile, "fr(%d),", n->u2.interop_int[i]);
+               else if (prefer_type[0] != ' ' || prefer_type[1] != '\0')
+                 fprintf (dumpfile, "fr(\"%s\"),", prefer_type);
+               prefer_type += 1 + strlen (prefer_type);
+
+               while (*prefer_type)
+                 {
+                   fprintf (dumpfile, "attr(\"%s\"),", prefer_type);
+                   prefer_type += 1 + strlen (prefer_type);
+                 }
+               fputc ('}', dumpfile);
+               ++prefer_type;
+               ++i;
+           }
+         if (n->u.init.len)
+           fputc (')', dumpfile);
+         fputc (':', dumpfile);
+       }
       fprintf (dumpfile, "%s", n->sym ? n->sym->name : "omp_all_memory");
       if (list_type == OMP_LIST_LINEAR && n->u.linear.op != OMP_LINEAR_DEFAULT)
        fputc (')', dumpfile);
@@ -1810,11 +1845,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
     fputs (" UNTIED", dumpfile);
   if (omp_clauses->mergeable)
     fputs (" MERGEABLE", dumpfile);
+  if (omp_clauses->nowait)
+    fputs (" NOWAIT", dumpfile);
   if (omp_clauses->collapse)
     fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse);
   for (list_type = 0; list_type < OMP_LIST_NUM; list_type++)
-    if (omp_clauses->lists[list_type] != NULL
-       && list_type != OMP_LIST_COPYPRIVATE)
+    if (omp_clauses->lists[list_type] != NULL)
       {
        const char *type = NULL;
        switch (list_type)
@@ -1859,6 +1895,9 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
          case OMP_LIST_SCAN_IN: type = "INCLUSIVE"; break;
          case OMP_LIST_SCAN_EX: type = "EXCLUSIVE"; break;
          case OMP_LIST_USES_ALLOCATORS: type = "USES_ALLOCATORS"; break;
+         case OMP_LIST_INIT: type = "INIT"; break;
+         case OMP_LIST_USE: type = "USE"; break;
+         case OMP_LIST_DESTROY: type = "DESTROY"; break;
          default:
            gcc_unreachable ();
          }
@@ -2190,6 +2229,7 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break;
     case EXEC_OMP_ERROR: name = "ERROR"; break;
     case EXEC_OMP_FLUSH: name = "FLUSH"; break;
+    case EXEC_OMP_INTEROP: name = "INTEROP"; break;
     case EXEC_OMP_LOOP: name = "LOOP"; break;
     case EXEC_OMP_MASKED: name = "MASKED"; break;
     case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break;
@@ -2291,6 +2331,7 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_ERROR:
+    case EXEC_OMP_INTEROP:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_ORDERED:
     case EXEC_OMP_MASKED:
@@ -2384,6 +2425,7 @@ show_omp_node (int level, gfc_code *c)
       || c->op == EXEC_OMP_TARGET_UPDATE || c->op == EXEC_OMP_TARGET_ENTER_DATA
       || c->op == EXEC_OMP_TARGET_EXIT_DATA || c->op == EXEC_OMP_SCAN
       || c->op == EXEC_OMP_DEPOBJ || c->op == EXEC_OMP_ERROR
+      || c->op == EXEC_OMP_INTEROP
       || (c->op == EXEC_OMP_ORDERED && c->block == NULL))
     return;
   if (c->op == EXEC_OMP_SECTIONS || c->op == EXEC_OMP_PARALLEL_SECTIONS)
@@ -2425,19 +2467,7 @@ show_omp_node (int level, gfc_code *c)
   fputc ('\n', dumpfile);
   code_indent (level, 0);
   fprintf (dumpfile, "!$%s END %s", is_oacc ? "ACC" : "OMP", name);
-  if (omp_clauses != NULL)
-    {
-      if (omp_clauses->lists[OMP_LIST_COPYPRIVATE])
-       {
-         fputs (" COPYPRIVATE(", dumpfile);
-         show_omp_namelist (OMP_LIST_COPYPRIVATE,
-                            omp_clauses->lists[OMP_LIST_COPYPRIVATE]);
-         fputc (')', dumpfile);
-       }
-      else if (omp_clauses->nowait)
-       fputs (" NOWAIT", dumpfile);
-    }
-  else if (c->op == EXEC_OMP_CRITICAL && c->ext.omp_clauses)
+  if (c->op == EXEC_OMP_CRITICAL && c->ext.omp_clauses)
     fprintf (dumpfile, " (%s)", c->ext.omp_clauses->critical_name);
 }
 
@@ -3553,6 +3583,7 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_ERROR:
+    case EXEC_OMP_INTEROP:
     case EXEC_OMP_FLUSH:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_MASKED:
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 9a36810fa61c..ed23818ea374 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -325,7 +325,7 @@ enum gfc_statement
   /* Note: gfc_match_omp_nothing returns ST_NONE. */
   ST_OMP_NOTHING, ST_NONE,
   ST_OMP_UNROLL, ST_OMP_END_UNROLL,
-  ST_OMP_TILE, ST_OMP_END_TILE
+  ST_OMP_TILE, ST_OMP_END_TILE, ST_OMP_INTEROP
 };
 
 /* Types of interfaces that we can have.  Assignment interfaces are
@@ -1390,6 +1390,13 @@ typedef struct gfc_omp_namelist
       struct gfc_symbol *memspace_sym;
       bool lastprivate_conditional;
       bool present_modifier;
+      struct
+       {
+         char *str;
+         int len;
+         bool target;
+         bool targetsync;
+       } init;
     } u;
   union
     {
@@ -1399,6 +1406,7 @@ typedef struct gfc_omp_namelist
       gfc_expr *allocator;
       struct gfc_symbol *traits_sym;
       struct gfc_omp_namelist *duplicate_of;
+      int *interop_int;
     } u2;
   struct gfc_omp_namelist *next;
   locus where;
@@ -1443,6 +1451,9 @@ enum
   OMP_LIST_HAS_DEVICE_ADDR,
   OMP_LIST_ENTER,
   OMP_LIST_USES_ALLOCATORS,
+  OMP_LIST_INIT,
+  OMP_LIST_USE,
+  OMP_LIST_DESTROY,
   OMP_LIST_NUM /* Must be the last.  */
 };
 
@@ -3103,7 +3114,7 @@ enum gfc_exec_op
   EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED,
   EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
   EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD, EXEC_OMP_SCOPE,
-  EXEC_OMP_UNROLL, EXEC_OMP_TILE, EXEC_OMP_METADIRECTIVE,
+  EXEC_OMP_UNROLL, EXEC_OMP_TILE, EXEC_OMP_METADIRECTIVE, EXEC_OMP_INTEROP,
   EXEC_OMP_ERROR, EXEC_OMP_ALLOCATE, EXEC_OMP_ALLOCATORS
 };
 
diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc
index 1f7d8f1b6ccd..859cdfc727ba 100644
--- a/gcc/fortran/match.cc
+++ b/gcc/fortran/match.cc
@@ -5545,8 +5545,10 @@ gfc_free_omp_namelist (gfc_omp_namelist *name, int list)
                      || list == OMP_LIST_FROM);
   bool free_align_allocator = (list == OMP_LIST_ALLOCATE);
   bool free_mem_traits_space = (list == OMP_LIST_USES_ALLOCATORS);
+  bool free_init = (list == OMP_LIST_INIT);
   gfc_omp_namelist *n;
   gfc_expr *last_allocator = NULL;
+  char *last_init_str = NULL;
 
   for (; name; name = n)
     {
@@ -5555,6 +5557,7 @@ gfc_free_omp_namelist (gfc_omp_namelist *name, int list)
        gfc_free_expr (name->u.align);
       else if (free_mem_traits_space)
        { }  /* name->u.memspace_sym: shall not call gfc_free_symbol here. */
+
       if (free_ns)
        gfc_free_namespace (name->u2.ns);
       else if (free_align_allocator)
@@ -5567,6 +5570,15 @@ gfc_free_omp_namelist (gfc_omp_namelist *name, int list)
        }
       else if (free_mem_traits_space)
        { }  /* name->u2.traits_sym: shall not call gfc_free_symbol here. */
+      else if (free_init)
+       {
+         if (name->u.init.str != last_init_str)
+           {
+             last_init_str = name->u.init.str;
+             free (name->u.init.str);
+             free (name->u2.interop_int);
+           }
+       }
       else if (free_mapper && name->u2.udm)
        free (name->u2.udm);
       else if (!free_mapper && name->u2.udr)
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index 6a37c8cff4b3..929fe73e7c98 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -174,6 +174,7 @@ match gfc_match_omp_do_simd (void);
 match gfc_match_omp_loop (void);
 match gfc_match_omp_error (void);
 match gfc_match_omp_flush (void);
+match gfc_match_omp_interop (void);
 match gfc_match_omp_masked (void);
 match gfc_match_omp_masked_taskloop (void);
 match gfc_match_omp_masked_taskloop_simd (void);
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index e869146517a2..beaf10123894 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -18,6 +18,8 @@ You should have received a copy of the GNU General Public 
License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define INCLUDE_VECTOR
+#define INCLUDE_STRING
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -78,7 +80,7 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
   /* "error" becomes GFC_OMP_DIR_EXECUTABLE with at(execution) */
   {"error", GFC_OMP_DIR_UTILITY, ST_OMP_ERROR},
   {"flush", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSH},
-  /* {"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP}, */
+  {"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP},
   {"loop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_LOOP},
   {"masked", GFC_OMP_DIR_EXECUTABLE, ST_OMP_MASKED},
   /* {"metadirective", GFC_OMP_DIR_META, ST_OMP_METADIRECTIVE}, */
@@ -1138,6 +1140,9 @@ enum omp_mask2
   OMP_CLAUSE_FULL,  /* OpenMP 5.1.  */
   OMP_CLAUSE_PARTIAL,  /* OpenMP 5.1.  */
   OMP_CLAUSE_SIZES,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_INIT,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_DESTROY,  /* OpenMP 5.1.  */
+  OMP_CLAUSE_USE,  /* OpenMP 5.1.  */
   /* This must come last.  */
   OMP_MASK2_LAST
 };
@@ -1897,6 +1902,325 @@ error:
 }
 
 
+/* Match the 'prefer_type' modifier of the interop 'init' clause:
+   with either OpenMP 5.1's
+     prefer_type ( <const-int-expr|string literal> [, ...]
+   or
+     prefer_type ( '{' <fr(...) | attr (...)>, ...] '}' [, '{' ... '}' ] )
+   where 'fr' takes an integer named constant or a string literal
+   and 'attr takes a string literal, starting with 'ompx_')
+
+Document string + int format
+*/
+
+static match
+gfc_match_omp_prefer_type (char **pref_str, int *pref_str_len, int 
**pref_int_array)
+{
+  gfc_expr *e;
+  size_t cnt = 0;
+  std::vector<int> int_list;
+  std::string pref_string;
+  /* New syntax.  */
+  if (gfc_peek_ascii_char () == '{')
+    do
+      {
+       if (gfc_match ("{ ") != MATCH_YES)
+         {
+           gfc_error ("Expected %<{%> at %C");
+           return MATCH_ERROR;
+         }
+       std::string attr;
+       bool fr_found = false;
+       do
+         {
+           if (gfc_match ("fr ( ") == MATCH_YES)
+             {
+               if (fr_found)
+                 {
+                   gfc_error ("Duplicated %<fr%> preference-selector-name "
+                              "at %C");
+                   return MATCH_ERROR;
+                 }
+               fr_found = true;
+               gfc_symbol *sym = NULL;
+               locus loc = gfc_current_locus;
+               if (gfc_match_symbol (&sym, 0) != MATCH_YES
+                   || gfc_match (" _") == MATCH_YES)
+                 {
+                   gfc_current_locus = loc;
+                   if (gfc_match_expr (&e) == MATCH_ERROR)
+                     return MATCH_ERROR;
+                 }
+               if ((!sym && !e)
+                   || (e && (!gfc_resolve_expr (e)
+                             || e->expr_type != EXPR_CONSTANT
+                             || e->ts.type != BT_CHARACTER
+                             || e->ts.kind != gfc_default_character_kind
+                             || e->value.character.length == 0))
+                   || (sym && (sym->attr.flavor != FL_PARAMETER
+                               || sym->ts.type != BT_INTEGER
+                               || !mpz_fits_sint_p (sym->value->value.integer)
+                               || sym->attr.dimension)))
+                 {
+                   gfc_error ("Expected constant integer identifier or "
+                              "non-empty default-kind character literal at %L",
+                              &e->where);
+                   gfc_free_expr (e);
+                   return MATCH_ERROR;
+                 }
+               if (sym)
+                 {
+                   for (size_t i = int_list.size(); i < cnt; ++i)
+                     int_list.push_back (0);
+                   int_list.push_back (mpz_get_si (sym->value->value.integer));
+                   pref_string += ' ';
+                   pref_string += '\0';
+                 }
+               else
+                 {
+                   char *str = XALLOCAVEC (char, e->value.character.length+1);
+                   for (int i = 0; i < e->value.character.length + 1; i++)
+                     str[i] = e->value.character.string[i];
+                  if (memchr (str, '\0', e->value.character.length) != 0)
+                    {
+                      gfc_error ("Unexpected null character in character "
+                                 "literal at %L", &loc);
+                      return MATCH_ERROR;
+                    }
+                   pref_string += str;
+                   pref_string += '\0';
+                 }
+             }
+           else if (gfc_match ("attr ( ") == MATCH_YES)
+             {
+               locus loc = gfc_current_locus;
+               if (gfc_match_expr (&e) != MATCH_YES
+                   || e->expr_type != EXPR_CONSTANT
+                   || e->ts.type != BT_CHARACTER)
+                 {
+                   gfc_error ("Expected default-kind character literal at %L",
+                              &loc);
+                   gfc_free_expr (e);
+                   return MATCH_ERROR;
+                 }
+               char *str = XALLOCAVEC (char, e->value.character.length+1);
+               for (int i = 0; i < e->value.character.length + 1; i++)
+                 str[i] = e->value.character.string[i];
+               if (!startswith (str, "ompx_"))
+                 {
+                   gfc_error ("Character literal at %L must start with "
+                             "%<ompx_%>", &e->where);
+                   gfc_free_expr (e);
+                   return MATCH_ERROR;
+                 }
+               if (memchr (str, '\0', e->value.character.length) != 0
+                   || memchr (str, ',', e->value.character.length) != 0)
+                 {
+                   gfc_error ("Unexpected null or %<,%> character in "
+                              "character literal at %L", &e->where);
+                   return MATCH_ERROR;
+                 }
+               attr += str;
+               attr += '\0';
+             }
+           else
+             {
+               gfc_error ("Expected %<fr(%> or %<attr(%> at %C");
+               return MATCH_ERROR;
+             }
+           ++cnt;
+           if (gfc_match (") ") != MATCH_YES)
+             {
+               gfc_error ("Expected %<)%> at %C");
+               return MATCH_ERROR;
+             }
+           if (gfc_match (", ") == MATCH_YES)
+             continue;
+           if (gfc_match ("} ") == MATCH_YES)
+             break;
+           gfc_error ("Expected %<,%> or %<}%> at %C");
+           return MATCH_ERROR;
+         }
+       while (true);
+       if (!fr_found)
+         {
+           pref_string += ' ';
+           pref_string += '\0';
+         }
+       pref_string += attr;
+       pref_string += '\0';
+
+       if (gfc_match (", ") == MATCH_YES)
+         continue;
+       if (gfc_match (") ") == MATCH_YES)
+         break;
+       gfc_error ("Expected %<,%> or %<)%> at %C");
+       return MATCH_ERROR;
+      }
+    while (true);
+  else
+    do
+      {
+       if (gfc_match_expr (&e) != MATCH_YES)
+         return MATCH_ERROR;
+       if (!gfc_resolve_expr (e)
+           || e->expr_type != EXPR_CONSTANT
+           || (e->ts.type != BT_INTEGER && e->ts.type != BT_CHARACTER)
+           || (e->ts.type == BT_INTEGER
+               && !mpz_fits_sint_p (e->value.integer))
+           || (e->ts.type == BT_CHARACTER
+               && (e->ts.kind != gfc_default_character_kind
+                   || e->value.character.length == 0)))
+         {
+           gfc_error ("Expected constant integer expression or non-empty "
+                      "default-kind character literal at %L", &e->where);
+           gfc_free_expr (e);
+           return MATCH_ERROR;
+         }
+       if (e->ts.type == BT_INTEGER)
+         {
+           for (size_t i = int_list.size(); i < cnt; ++i)
+             int_list.push_back (0);
+           int_list.push_back (mpz_get_si (e->value.integer));
+           pref_string += ' ';
+         }
+       else
+         {
+           char *str = XALLOCAVEC (char, e->value.character.length+1);
+           for (int i = 0; i < e->value.character.length + 1; i++)
+             str[i] = e->value.character.string[i];
+           if (memchr (str, '\0', e->value.character.length) != 0)
+             {
+               gfc_error ("Unexpected null character in character literal "
+                          "at %L", &e->where);
+               return MATCH_ERROR;
+             }
+           pref_string += str;
+         }
+       pref_string += '\0';
+       pref_string += '\0';
+       ++cnt;
+       gfc_free_expr (e);
+       if (gfc_match (", ") == MATCH_YES)
+         continue;
+       if (gfc_match (") ") == MATCH_YES)
+         break;
+       gfc_error ("Expected %<,%> or %<)%> at %C");
+       return MATCH_ERROR;
+      }
+    while (true);
+  if (!int_list.empty())
+    for (size_t i = int_list.size(); i < cnt; ++i)
+     int_list.push_back (0);
+
+  pref_string += '\0';
+
+  *pref_str_len = pref_string.length();
+  *pref_str = XNEWVEC (char, pref_string.length ());
+  memcpy (*pref_str, pref_string.data (), pref_string.length ());
+  if (!int_list.empty ())
+    {
+      *pref_int_array = XNEWVEC (int, cnt);
+      memcpy (*pref_int_array, int_list.data (), sizeof (int) * cnt);
+    }
+  return MATCH_YES;
+}
+
+
+/* Match OpenMP 5.1's 'init' clause for 'interop' objects:
+   init([prefer_type(...)][,][<target|targetsync>, ...] :] interop-obj-list)  
*/
+
+static match
+gfc_match_omp_init (gfc_omp_namelist **list)
+{
+  bool target = false, targetsync = false;
+  char *pref_str = NULL;
+  int pref_str_len = 0;
+  int *pref_int_array = NULL;
+  match m;
+  locus old_loc = gfc_current_locus;
+  do {
+       if (gfc_match ("prefer_type ( ") == MATCH_YES)
+       {
+         if (pref_str)
+           {
+             gfc_error ("Duplicate %<prefer_type%> modifier at %C");
+             return MATCH_ERROR;
+           }
+         m = gfc_match_omp_prefer_type (&pref_str, &pref_str_len,
+                                        &pref_int_array);
+         if (m != MATCH_YES)
+           return m;
+         if (gfc_match (", ") == MATCH_YES)
+           continue;
+         if (gfc_match (": ") == MATCH_YES)
+           break;
+         gfc_error ("Expected %<,%> or %<:%> at %C");
+         return MATCH_ERROR;
+       }
+       if (gfc_match ("targetsync ") == MATCH_YES)
+       {
+         targetsync = true;
+         if (gfc_match (", ") == MATCH_YES)
+           continue;
+         if (gfc_match (": ") == MATCH_YES)
+           break;
+         gfc_char_t c = gfc_peek_char ();
+         if (!pref_str
+             && (c == ')'
+                 || (gfc_current_form != FORM_FREE
+                     && (c == '_' || ISALPHA (c)))))
+           {
+             gfc_current_locus = old_loc;
+             break;
+           }
+         gfc_error ("Expected %<,%> or %<:%> at %C");
+         return MATCH_ERROR;
+       }
+      if (gfc_match ("target ") == MATCH_YES)
+       {
+         target = true;
+         if (gfc_match (", ") == MATCH_YES)
+           continue;
+         if (gfc_match (": ") == MATCH_YES)
+           break;
+         gfc_char_t c = gfc_peek_char ();
+         if (!pref_str
+             && (c == ')'
+                 || (gfc_current_form != FORM_FREE
+                     && (c == '_' || ISALPHA (c)))))
+           {
+             gfc_current_locus = old_loc;
+             break;
+           }
+         gfc_error ("Expected %<,%> or %<:%> at %C");
+         return MATCH_ERROR;
+       }
+      if (pref_str)
+       {
+         gfc_error ("Expected %<target%> or %<targetsync%> at %C");
+         return MATCH_ERROR;
+       }
+      gfc_current_locus = old_loc;
+      break;
+    }
+  while (true);
+
+ gfc_omp_namelist **head = NULL;
+ if (gfc_match_omp_variable_list ("", list, false, NULL, &head) != MATCH_YES)
+   return MATCH_ERROR;
+ for (gfc_omp_namelist *n = *head; n; n = n->next)
+   {
+     n->u.init.target = target;
+     n->u.init.targetsync = targetsync;
+     n->u.init.str = pref_str;
+     n->u.init.len = pref_str_len;
+     n->u2.interop_int = pref_int_array;
+   }
+ return MATCH_YES;
+}
+
+
 /* Match with duplicate check. Matches 'name'. If expr != NULL, it
    then matches '(expr)', otherwise, if open_parens is true,
    it matches a ' ( ' after 'name'.
@@ -2620,6 +2944,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                }
              continue;
            }
+         if ((mask & OMP_CLAUSE_DESTROY)
+             && gfc_match_omp_variable_list ("destroy (",
+                                             &c->lists[OMP_LIST_DESTROY],
+                                             true) == MATCH_YES)
+           continue;
          if ((mask & OMP_CLAUSE_DETACH)
              && !openacc
              && !c->detach
@@ -2983,6 +3312,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
                c->indirect = 1;
              continue;
            }
+         if ((mask & OMP_CLAUSE_INIT)
+             && gfc_match ("init ( ") == MATCH_YES)
+           {
+             m = gfc_match_omp_init (&c->lists[OMP_LIST_INIT]);
+             if (m == MATCH_YES)
+               continue;
+             goto error;
+           }
          if ((mask & OMP_CLAUSE_IS_DEVICE_PTR)
              && gfc_match_omp_variable_list
                   ("is_device_ptr (",
@@ -3934,6 +4271,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const 
omp_mask mask,
              needs_space = true;
              continue;
            }
+         if ((mask & OMP_CLAUSE_USE)
+             && gfc_match_omp_variable_list ("use (",
+                                             &c->lists[OMP_LIST_USE],
+                                             true) == MATCH_YES)
+           continue;
          if ((mask & OMP_CLAUSE_USE_DEVICE)
              && gfc_match_omp_variable_list ("use_device (",
                                              &c->lists[OMP_LIST_USE_DEVICE],
@@ -4748,6 +5090,9 @@ cleanup:
   (omp_mask (OMP_CLAUSE_SIZES))
 #define OMP_ALLOCATORS_CLAUSES \
   omp_mask (OMP_CLAUSE_ALLOCATE)
+#define OMP_INTEROP_CLAUSES \
+  (omp_mask (OMP_CLAUSE_DEPEND) | OMP_CLAUSE_NOWAIT | OMP_CLAUSE_DEVICE \
+   | OMP_CLAUSE_INIT | OMP_CLAUSE_DESTROY | OMP_CLAUSE_USE)
 
 
 static match
@@ -6073,6 +6418,14 @@ gfc_ignore_trait_property_extension_list (void)
     }
 }
 
+
+match
+gfc_match_omp_interop (void)
+{
+  return match_omp (EXEC_OMP_INTEROP, OMP_INTEROP_CLAUSES);
+}
+
+
 /* OpenMP 5.0:
 
    trait-selector:
@@ -8821,7 +9174,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
        "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
        "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
        "NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
-       "USES_ALLOCATORS" };
+       "USES_ALLOCATORS", "INIT", "USE", "DESTROY" };
   STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM);
 
   if (omp_clauses == NULL)
@@ -9039,6 +9392,29 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
     gfc_error ("DEPOBJ in DEPOBJ construct at %L shall be a scalar integer "
               "of OMP_DEPEND_KIND kind", &omp_clauses->depobj->where);
 
+  if (code
+      && code->op == EXEC_OMP_INTEROP
+      && omp_clauses->lists[OMP_LIST_DEPEND])
+    {
+      if (!omp_clauses->lists[OMP_LIST_INIT]
+         && !omp_clauses->lists[OMP_LIST_USE]
+         && !omp_clauses->lists[OMP_LIST_DESTROY])
+       {
+         gfc_error ("DEPEND clause at %L requires action clause with "
+                    "%<targetsync%> interop-type",
+                    &omp_clauses->lists[OMP_LIST_DEPEND]->where);
+       }
+      for (n = omp_clauses->lists[OMP_LIST_INIT]; n; n = n->next)
+       if (!n->u.init.targetsync)
+         {
+           gfc_error ("DEPEND clause at %L requires %<targetsync%> "
+                      "interop-type, lacking it for %qs at %L",
+                      &omp_clauses->lists[OMP_LIST_DEPEND]->where,
+                      n->sym->name, &n->where);
+           break;
+         }
+    }
+
   verify_omp_clauses_symbol_dups (code, omp_clauses, ns, openacc);
 
   /* OpenACC reductions.  */
@@ -11868,6 +12244,8 @@ omp_code_to_statement (gfc_code *code)
       return ST_OMP_ERROR;
     case EXEC_OMP_FLUSH:
       return ST_OMP_FLUSH;
+    case EXEC_OMP_INTEROP:
+      return ST_OMP_INTEROP;
     case EXEC_OMP_DISTRIBUTE:
       return ST_OMP_DISTRIBUTE;
     case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
@@ -12445,6 +12823,7 @@ gfc_resolve_omp_directive (gfc_code *code, 
gfc_namespace *ns)
     case EXEC_OMP_ASSUME:
     case EXEC_OMP_CANCEL:
     case EXEC_OMP_ERROR:
+    case EXEC_OMP_INTEROP:
     case EXEC_OMP_MASKED:
     case EXEC_OMP_ORDERED:
     case EXEC_OMP_PARALLEL_WORKSHARE:
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index 1a758405228f..182c293148d5 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -1180,6 +1180,9 @@ decode_omp_directive (void)
     case 'f':
       matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH);
       break;
+    case 'i':
+      matcho ("interop", gfc_match_omp_interop, ST_OMP_INTEROP);
+      break;
     case 'm':
       matcho ("masked taskloop simd", gfc_match_omp_masked_taskloop_simd,
              ST_OMP_MASKED_TASKLOOP_SIMD);
@@ -1908,6 +1911,7 @@ next_statement (void)
   case ST_OMP_CANCEL: case ST_OMP_CANCELLATION_POINT: case ST_OMP_DEPOBJ: \
   case ST_OMP_TARGET_UPDATE: case ST_OMP_TARGET_ENTER_DATA: \
   case ST_OMP_TARGET_EXIT_DATA: case ST_OMP_ORDERED_DEPEND: case ST_OMP_ERROR: 
\
+  case ST_OMP_INTEROP: \
   case ST_ERROR_STOP: case ST_OMP_SCAN: case ST_SYNC_ALL: \
   case ST_SYNC_IMAGES: case ST_SYNC_MEMORY: case ST_LOCK: case ST_UNLOCK: \
   case ST_FORM_TEAM: case ST_CHANGE_TEAM: \
@@ -2884,6 +2888,9 @@ gfc_ascii_statement (gfc_statement st, bool 
strip_sentinel)
     case ST_OMP_FLUSH:
       p = "!$OMP FLUSH";
       break;
+    case ST_OMP_INTEROP:
+      p = "!$OMP INTEROP";
+      break;
     case ST_OMP_LOOP:
       p = "!$OMP LOOP";
       break;
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 383a34117759..ac81f10f1516 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -13106,6 +13106,7 @@ start:
        case EXEC_OMP_DO:
        case EXEC_OMP_DO_SIMD:
        case EXEC_OMP_ERROR:
+       case EXEC_OMP_INTEROP:
        case EXEC_OMP_LOOP:
        case EXEC_OMP_MASTER:
        case EXEC_OMP_MASTER_TASKLOOP:
diff --git a/gcc/fortran/st.cc b/gcc/fortran/st.cc
index 83533db6e4d2..6db632b00c04 100644
--- a/gcc/fortran/st.cc
+++ b/gcc/fortran/st.cc
@@ -229,6 +229,7 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_DO:
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_ERROR:
+    case EXEC_OMP_INTEROP:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_END_SINGLE:
     case EXEC_OMP_MASKED_TASKLOOP:
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index e6ba7b5839e3..d96dc17a05f4 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -10910,6 +10910,9 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_teams (code, NULL, NULL_TREE);
     case EXEC_OMP_WORKSHARE:
       return gfc_trans_omp_workshare (code, code->ext.omp_clauses);
+    case EXEC_OMP_INTEROP:
+      sorry ("%<!$OMP INTEROP%>");
+      return build_empty_stmt (input_location);
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc
index 49b021606717..342b65092b02 100644
--- a/gcc/fortran/trans.cc
+++ b/gcc/fortran/trans.cc
@@ -2602,9 +2602,10 @@ trans_code (gfc_code * code, tree cond)
        case EXEC_OMP_DISTRIBUTE_SIMD:
        case EXEC_OMP_DO:
        case EXEC_OMP_DO_SIMD:
-       case EXEC_OMP_LOOP:
        case EXEC_OMP_ERROR:
        case EXEC_OMP_FLUSH:
+       case EXEC_OMP_INTEROP:
+       case EXEC_OMP_LOOP:
        case EXEC_OMP_MASKED:
        case EXEC_OMP_MASKED_TASKLOOP:
        case EXEC_OMP_MASKED_TASKLOOP_SIMD:
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index d624f84bd3f2..0f0bacf153e8 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,12 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-06  Tobias Burnus  <tbur...@baylibre.com>
+
+       * gfortran.dg/gomp/interop-1.f90: New test.
+       * gfortran.dg/gomp/interop-2.f90: New test.
+       * gfortran.dg/gomp/interop-3.f90: New test.
+
 2024-12-19  Thomas Schwinge  <tschwi...@baylibre.com>
 
        PR target/65181
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-1.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-1.f90
new file mode 100644
index 000000000000..bbb1dea1be62
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-1.f90
@@ -0,0 +1,62 @@
+module m
+ use iso_c_binding
+ implicit none
+
+ ! The following definitions are in omp_lib, which cannot be included
+ ! in gcc/testsuite/
+ integer, parameter :: omp_interop_kind = c_intptr_t
+ integer, parameter :: omp_interop_fr_kind = c_int
+
+ integer (omp_interop_kind), parameter :: omp_interop_none = 0_omp_interop_kind
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda = 1
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda_driver = 2
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_opencl = 3
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_sycl = 4
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hip = 5
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_level_zero = 6
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hsa = 7
+end module m
+
+subroutine sub1
+  !$omp interop
+  integer :: y ! { dg-error "Unexpected data declaration statement" }
+end subroutine sub1
+
+program main
+use m
+implicit none
+
+!$omp requires reverse_offload
+
+integer(omp_interop_kind) :: obj1, obj2, obj3, obj4, obj5
+integer :: x
+
+!$omp interop init(obj1) init(target,targetsync,target,targetsync : obj2, 
obj3) nowait
+
+!$omp interop init(prefer_type("cu"//"da", omp_ifr_opencl, omp_ifr_level_zero, 
"hsa"), targetsync : obj1) &
+!$omp&        destroy(obj2, obj3) depend(inout: x) use(obj4, obj5) 
device(device_num: 0)
+
+!$omp assume contains(interop)
+  !$omp interop init(prefer_type("cu"//char(1)//"da") : obj3)
+!$omp end assume
+
+!$omp interop init(prefer_type("cu"//char(0)//"da") : obj3) ! { dg-error 
"Unexpected null character in character literal" }
+
+!$omp interop depend(inout: x) , use(obj2), destroy(obj3) !  OK, use or 
destory might have 'targetsync'
+
+!$omp interop depend(inout: x) use(obj2), destroy(obj3) !  Likewise
+
+!$omp interop depend(inout: x) init(targetsync : obj5)  use(obj2), 
destroy(obj3) init(prefer_type("cuda"), targetsync : obj4) ! OK
+
+!$omp interop init ( target , prefer_type( { fr("hsa") }, "hip") : obj1) ! { 
dg-error "Expected '\{' at .1." }
+
+!$omp interop init ( target , prefer_type( { fr("hsa"), attr("ompx_nothing") , 
fr("hsa" ) }) :obj1) ! { dg-error "Duplicated 'fr' preference-selector-name" }
+
+!$omp interop init ( prefer_type( 4, omp_ifr_hip*4) : obj1)
+!$omp interop init ( prefer_type( sin(3.3) : obj1)  ! { dg-error "Expected 
constant integer expression or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( {fr(4) }) : obj1) ! { dg-error "Expected 
constant integer identifier or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( {fr(4_"cuda") }) : obj1) ! { dg-error 
"Expected constant integer identifier or non-empty default-kind character 
literal" }
+!$omp interop init ( prefer_type( {fr(c_char_"cuda") }) : obj1) ! OK
+!$omp interop init ( prefer_type( {fr(1_"cuda") }) : obj1) ! OK
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-2.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-2.f90
new file mode 100644
index 000000000000..c7673a662d0c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-2.f90
@@ -0,0 +1,46 @@
+module m
+ use iso_c_binding
+ implicit none
+
+ ! The following definitions are in omp_lib, which cannot be included
+ ! in gcc/testsuite/
+ integer, parameter :: omp_interop_kind = c_intptr_t
+ integer, parameter :: omp_interop_fr_kind = c_int
+
+ integer (omp_interop_kind), parameter :: omp_interop_none = 0_omp_interop_kind
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda = 1
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda_driver = 2
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_opencl = 3
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_sycl = 4
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hip = 5
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_level_zero = 6
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hsa = 7
+end module m
+
+program main
+use m
+implicit none
+
+!$omp requires reverse_offload
+
+integer(omp_interop_kind) :: obj1, obj2, obj3, obj4, obj5
+integer :: x
+
+!$omp interop init ( prefer_type( {fr(1_"") }) : obj1) ! { dg-error "Expected 
constant integer identifier or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr(omp_ifr_cuda) }) : obj1) 
! { dg-error "Expected default-kind character literal" }
+
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr("myooption") }) : obj1) 
! { dg-error "Character literal at .1. must start with 'ompx_'" }
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr("ompx_option") , 
attr("ompx_") } ) : obj1)
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr("ompx_option") }, { 
attr("ompx_") } ) : obj1)
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr("ompx_option") }  { 
attr("ompx_") } ) : obj1) ! { dg-error "Expected ',' or '\\)'" }
+!$omp interop init ( prefer_type( {fr(1_"hip") , attr("ompx_option")   ) : 
obj1) ! { dg-error "Expected ',' or '\}'" }
+
+!$omp interop init ( prefer_type( {fr(1_"hip") attr("ompx_option")   ) : obj1) 
! { dg-error "Expected ',' or '\}'" }
+!$omp interop init ( prefer_type( {fr(1_"hip")}), prefer_type("cuda") : obj1) 
! { dg-error "Duplicate 'prefer_type' modifier" }
+
+!$omp interop init ( prefer_type( {attr("ompx_option1,ompx_option2")   ) : 
obj1) ! { dg-error "Unexpected null or ',' character in character literal" }
+
+!$omp interop init ( targetsync other ) : obj1)  ! { dg-error "Expected ',' or 
':'" }
+!$omp interop init ( prefer_type( {fr(1_"cuda") } ), other : obj1)  ! { 
dg-error "Expected 'target' or 'targetsync'" }
+!$omp interop init ( prefer_type( {fr(1_"cuda") } ), obj1)  ! { dg-error 
"Expected 'target' or 'targetsync'" }
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-3.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-3.f90
new file mode 100644
index 000000000000..a6d2cc460fb0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-3.f90
@@ -0,0 +1,59 @@
+module m
+ use iso_c_binding
+ implicit none
+
+ ! The following definitions are in omp_lib, which cannot be included
+ ! in gcc/testsuite/
+ integer, parameter :: omp_interop_kind = c_intptr_t
+ integer, parameter :: omp_interop_fr_kind = c_int
+
+ integer (omp_interop_kind), parameter :: omp_interop_none = 0_omp_interop_kind
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda = 1
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_cuda_driver = 2
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_opencl = 3
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_sycl = 4
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hip = 5
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_level_zero = 6
+ integer (omp_interop_fr_kind), parameter :: omp_ifr_hsa = 7
+end module m
+
+program main
+use m
+implicit none
+
+!$omp requires reverse_offload
+
+integer(omp_interop_kind) :: obj1, obj2, obj3, obj4, obj5
+integer(omp_interop_kind) :: target, targetsync,prefer_type
+integer :: x
+
+!$omp interop init(obj1) init(target,targetsync,target,targetsync : obj2, 
obj3) nowait
+
+!$omp interop init(prefer_type("cu"//"da", omp_ifr_opencl, omp_ifr_level_zero, 
"hsa"), targetsync : obj1) &
+!$omp&        destroy(obj2, obj3) depend(inout: x) use(obj4, obj5) 
device(device_num: 0)
+
+!$omp assume contains(interop)
+  !$omp interop init(prefer_type("cu"//char(1)//"da") : obj3)
+!$omp end assume
+
+!$omp interop init(obj1, obj2, obj1), use(obj4) destroy(obj4)
+! { dg-error "Symbol 'obj1' present on multiple clauses" "" { target *-*-* } 
.-1 }
+! { dg-error "Symbol 'obj4' present on multiple clauses" "" { target *-*-* } 
.-2 }
+
+!$omp interop depend(inout: x)  ! { dg-error "DEPEND clause at .1. requires 
action clause with 'targetsync' interop-type" }
+
+!$omp interop depend(inout: x) , use(obj2), destroy(obj3) !  OK, use or 
destory might have 'targetsync'
+
+!$omp interop depend(inout: x) use(obj2), destroy(obj3) !  Likewise
+
+!$omp interop depend(inout: x) use(obj2), destroy(obj3) init(obj4) ! { 
dg-error "DEPEND clause at .1. requires 'targetsync' interop-type, lacking it 
for 'obj4' at .2." }
+
+!$omp interop depend(inout: x) init(targetsync : obj5)  use(obj2), 
destroy(obj3) init(obj4) ! { dg-error "DEPEND clause at .1. requires 
'targetsync' interop-type, lacking it for 'obj4' at .2." } 
+!$omp interop depend(inout: x) init(targetsync : obj5)  use(obj2), 
destroy(obj3) init(prefer_type("cuda"), targetsync : obj4) ! OK
+
+!$omp interop init(target, targetsync, prefer_type, obj1)
+!$omp interop init(prefer_type, obj1, target, targetsync)
+!$omp interop init(target, targetsync,target)  ! { dg-error "Symbol 'target' 
present on multiple clauses" }
+
+!$omp interop init(, targetsync, prefer_type, obj1, target)  ! { dg-error 
"Syntax error in OpenMP variable list" }
+end
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index c536093070ce..1c4e2385c0f9 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,39 +1,3 @@
-2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
-
-       Backported from master:
-       2024-08-28  Tobias Burnus  <tbur...@baylibre.com>
-
-       * fortran.c (omp_get_interop_str_, omp_get_interop_name_,
-       omp_get_interop_type_desc_, omp_get_interop_rc_desc_): Add.
-       * libgomp.map (GOMP_5.1.3): New; add interop routines.
-       * omp.h.in: Add interop typedefs, enum and prototypes.
-       (__GOMP_DEFAULT_NULL): Define.
-       (omp_target_memcpy_async, omp_target_memcpy_rect_async):
-       Use it for the optional depend argument.
-       * omp_lib.f90.in: Add paramters and interfaces for interop.
-       * omp_lib.h.in: Likewise; move F90 '&' to column 81 for
-       -ffree-length-80.
-       * target.c (omp_get_num_interop_properties, omp_get_interop_int,
-       omp_get_interop_ptr, omp_get_interop_str, omp_get_interop_name,
-       omp_get_interop_type_desc, omp_get_interop_rc_desc): Add.
-       * config/gcn/target.c (omp_get_num_interop_properties,
-       omp_get_interop_int, omp_get_interop_ptr, omp_get_interop_str,
-       omp_get_interop_name, omp_get_interop_type_desc,
-       omp_get_interop_rc_desc): Add.
-       * config/nvptx/target.c (omp_get_num_interop_properties,
-       omp_get_interop_int, omp_get_interop_ptr, omp_get_interop_str,
-       omp_get_interop_name, omp_get_interop_type_desc,
-       omp_get_interop_rc_desc): Add.
-       * testsuite/libgomp.c-c++-common/interop-routines-1.c: New test.
-       * testsuite/libgomp.c-c++-common/interop-routines-2.c: New test.
-       * testsuite/libgomp.fortran/interop-routines-1.F90: New test.
-       * testsuite/libgomp.fortran/interop-routines-2.F90: New test.
-       * testsuite/libgomp.fortran/interop-routines-3.F: New test.
-       * testsuite/libgomp.fortran/interop-routines-4.F: New test.
-       * testsuite/libgomp.fortran/interop-routines-5.F: New test.
-       * testsuite/libgomp.fortran/interop-routines-6.F: New test.
-       * testsuite/libgomp.fortran/interop-routines-7.F90: New test.
-
 2024-08-05  Paul Thomas  <pa...@gcc.gnu.org>
 
        Backported from master:
diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index ddd6fda24491..da75f4eda917 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,39 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-08-28  Tobias Burnus  <tbur...@baylibre.com>
+
+       * fortran.c (omp_get_interop_str_, omp_get_interop_name_,
+       omp_get_interop_type_desc_, omp_get_interop_rc_desc_): Add.
+       * libgomp.map (GOMP_5.1.3): New; add interop routines.
+       * omp.h.in: Add interop typedefs, enum and prototypes.
+       (__GOMP_DEFAULT_NULL): Define.
+       (omp_target_memcpy_async, omp_target_memcpy_rect_async):
+       Use it for the optional depend argument.
+       * omp_lib.f90.in: Add paramters and interfaces for interop.
+       * omp_lib.h.in: Likewise; move F90 '&' to column 81 for
+       -ffree-length-80.
+       * target.c (omp_get_num_interop_properties, omp_get_interop_int,
+       omp_get_interop_ptr, omp_get_interop_str, omp_get_interop_name,
+       omp_get_interop_type_desc, omp_get_interop_rc_desc): Add.
+       * config/gcn/target.c (omp_get_num_interop_properties,
+       omp_get_interop_int, omp_get_interop_ptr, omp_get_interop_str,
+       omp_get_interop_name, omp_get_interop_type_desc,
+       omp_get_interop_rc_desc): Add.
+       * config/nvptx/target.c (omp_get_num_interop_properties,
+       omp_get_interop_int, omp_get_interop_ptr, omp_get_interop_str,
+       omp_get_interop_name, omp_get_interop_type_desc,
+       omp_get_interop_rc_desc): Add.
+       * testsuite/libgomp.c-c++-common/interop-routines-1.c: New test.
+       * testsuite/libgomp.c-c++-common/interop-routines-2.c: New test.
+       * testsuite/libgomp.fortran/interop-routines-1.F90: New test.
+       * testsuite/libgomp.fortran/interop-routines-2.F90: New test.
+       * testsuite/libgomp.fortran/interop-routines-3.F: New test.
+       * testsuite/libgomp.fortran/interop-routines-4.F: New test.
+       * testsuite/libgomp.fortran/interop-routines-5.F: New test.
+       * testsuite/libgomp.fortran/interop-routines-6.F: New test.
+       * testsuite/libgomp.fortran/interop-routines-7.F90: New test.
+
 2024-12-19  Thomas Schwinge  <tschwi...@baylibre.com>
 
        PR target/65181

Reply via email to