https://gcc.gnu.org/g:2b5d2e573171bf51ca902045ce3e5be654ea3d37

commit 2b5d2e573171bf51ca902045ce3e5be654ea3d37
Author: Tobias Burnus <tbur...@baylibre.com>
Date:   Thu Jan 23 22:31:42 2025 +0100

    Fortran: Fixes to OpenMP 'interop' directive parsing support
    
    Handle lists as argument to 'fr' and 'attr'; fix parsing corner cases.
    Additionally, 'fr' values are now internally stored as integer, permitting
    the diagnoses (warning) for values not defined in the OpenMP additional
    definitions document.
    
            PR fortran/116661
    
    gcc/fortran/ChangeLog:
    
            * gfortran.h (gfc_omp_namelist): Rename 'init' members for clarity.
            * match.cc (gfc_free_omp_namelist): Handle renaming.
            * dump-parse-tree.cc (show_omp_namelist): Update for new format
            and features.
            * openmp.cc (gfc_match_omp_prefer_type): Parse list to 'fr' and 
'attr';
            store 'fr' values as integer.
            (gfc_match_omp_init): Rename variable names.
    
    gcc/ChangeLog:
    
            * omp-api.h (omp_get_fr_id_from_name, omp_get_name_from_fr_id): New
            prototypes.
            * omp-general.cc (omp_get_fr_id_from_name, omp_get_name_from_fr_id):
            New.
    
    include/ChangeLog:
    
            * gomp-constants.h (GOMP_INTEROP_IFR_LAST,
            GOMP_INTEROP_IFR_SEPARATOR, GOMP_INTEROP_IFR_NONE): New.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/gomp/interop-1.f90: Extend, update dg-*.
            * gfortran.dg/gomp/interop-2.f90: Update dg-error.
            * gfortran.dg/gomp/interop-3.f90: Add dg-warning.
    
    (cherry picked from commit 99988464fc86354f0359c0fd91eee444fb5bd8a2)

Diff:
---
 gcc/ChangeLog.omp                            |  11 +
 gcc/fortran/ChangeLog.omp                    |  14 ++
 gcc/fortran/dump-parse-tree.cc               |  84 +++++---
 gcc/fortran/gfortran.h                       |   4 +-
 gcc/fortran/match.cc                         |  10 +-
 gcc/fortran/openmp.cc                        | 305 ++++++++++++++++-----------
 gcc/omp-api.h                                |   3 +
 gcc/omp-general.cc                           |  29 +++
 gcc/testsuite/ChangeLog.omp                  |  10 +
 gcc/testsuite/gfortran.dg/gomp/interop-1.f90 |  32 ++-
 gcc/testsuite/gfortran.dg/gomp/interop-2.f90 |   2 +-
 gcc/testsuite/gfortran.dg/gomp/interop-3.f90 |   2 +-
 include/ChangeLog.omp                        |   9 +
 include/gomp-constants.h                     |   5 +
 14 files changed, 358 insertions(+), 162 deletions(-)

diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index 5591b79d60e6..73eb15105039 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -1,3 +1,14 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-13  Tobias Burnus  <tbur...@baylibre.com>
+
+       PR fortran/116661
+       * omp-api.h (omp_get_fr_id_from_name, omp_get_name_from_fr_id): New
+       prototypes.
+       * omp-general.cc (omp_get_fr_id_from_name, omp_get_name_from_fr_id):
+       New.
+
 2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 0d353d55957d..89cc5f52ebb6 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,17 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-13  Tobias Burnus  <tbur...@baylibre.com>
+
+       PR fortran/116661
+       * gfortran.h (gfc_omp_namelist): Rename 'init' members for clarity.
+       * match.cc (gfc_free_omp_namelist): Handle renaming.
+       * dump-parse-tree.cc (show_omp_namelist): Update for new format
+       and features.
+       * openmp.cc (gfc_match_omp_prefer_type): Parse list to 'fr' and 'attr';
+       store 'fr' values as integer.
+       (gfc_match_omp_init): Rename variable names.
+
 2025-01-23  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 595f9c3c7c12..f09fb4eb6abc 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "constructor.h"
 #include "version.h"
 #include "parse.h"  /* For gfc_ascii_statement.  */
+#include "omp-api.h"  /* For omp_get_name_from_fr_id.  */
+#include "gomp-constants.h"  /* For GOMP_INTEROP_IFR_SEPARATOR.  */
 
 /* Keep track of indentation for symbol tree dumps.  */
 static int show_level = 0;
@@ -1533,35 +1535,69 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
        }
       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->u2.init_interop_fr)
+           {
+             char *attr_str = n->u.init.attr;
+             int idx = 0;
+             int fr_id;
+             fputs ("prefer_type(", dumpfile);
+             do
+               {
+                 fr_id = n->u2.init_interop_fr[idx];
+                 fputc ('{', dumpfile);
+                 if (fr_id != GOMP_INTEROP_IFR_NONE)
+                   {
+                     fputs ("fr(", dumpfile);
+                     do
+                       {
+                         const char *fr_str = omp_get_name_from_fr_id (fr_id);
+                         if (fr_str)
+                           fprintf (dumpfile, "\"%s\"", fr_str);
+                         else
+                           fprintf (dumpfile, "%d", fr_id);
+                         fr_id = n->u2.init_interop_fr[++idx];
+                         if (fr_id != GOMP_INTEROP_IFR_SEPARATOR)
+                           fputc (',', dumpfile);
+                       }
+                     while (fr_id != GOMP_INTEROP_IFR_SEPARATOR);
+                     fputc (')', dumpfile);
+                     if (attr_str && (attr_str[0] != ' ' || attr_str[1] != 
'\0'))
+                       fputc (',', dumpfile);
+                   }
+                 else
+                   fr_id = n->u2.init_interop_fr[++idx];
+                 if (attr_str && attr_str[0] == ' ' && attr_str[1] == '\0')
+                   attr_str += 2;
+                 else if (attr_str)
+                   {
+                     fputs ("attr(\"", dumpfile);
+                     do
+                       {
+                         fputs ((char *) attr_str, dumpfile);
+                         fputc ('"', dumpfile);
+                         attr_str += strlen (attr_str) + 1;
+                         if (attr_str[0] == '\0')
+                           break;
+                         fputs (",\"", dumpfile);
+                       }
+                     while (true);
+                     fputc (')', dumpfile);
+                   }
+                 fputc ('}', dumpfile);
+                 fr_id = n->u2.init_interop_fr[++idx];
+                 if (fr_id == GOMP_INTEROP_IFR_SEPARATOR)
+                   break;
+                 fputc (',', dumpfile);
+                 if (attr_str)
+                   ++attr_str;
+               }
+             while (true);
+             fputc (')', dumpfile);
            }
-         if (n->u.init.len)
-           fputc (')', dumpfile);
          fputc (':', dumpfile);
        }
       fprintf (dumpfile, "%s", n->sym ? n->sym->name : "omp_all_memory");
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index ed23818ea374..34dcb4e44c7b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1392,7 +1392,7 @@ typedef struct gfc_omp_namelist
       bool present_modifier;
       struct
        {
-         char *str;
+         char *attr;
          int len;
          bool target;
          bool targetsync;
@@ -1406,7 +1406,7 @@ typedef struct gfc_omp_namelist
       gfc_expr *allocator;
       struct gfc_symbol *traits_sym;
       struct gfc_omp_namelist *duplicate_of;
-      int *interop_int;
+      char *init_interop_fr;
     } u2;
   struct gfc_omp_namelist *next;
   locus where;
diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc
index 859cdfc727ba..3ae0f72a00ad 100644
--- a/gcc/fortran/match.cc
+++ b/gcc/fortran/match.cc
@@ -5548,7 +5548,7 @@ gfc_free_omp_namelist (gfc_omp_namelist *name, int list)
   bool free_init = (list == OMP_LIST_INIT);
   gfc_omp_namelist *n;
   gfc_expr *last_allocator = NULL;
-  char *last_init_str = NULL;
+  char *last_init_attr = NULL;
 
   for (; name; name = n)
     {
@@ -5572,11 +5572,11 @@ gfc_free_omp_namelist (gfc_omp_namelist *name, int list)
        { }  /* name->u2.traits_sym: shall not call gfc_free_symbol here. */
       else if (free_init)
        {
-         if (name->u.init.str != last_init_str)
+         if (name->u.init.attr != last_init_attr)
            {
-             last_init_str = name->u.init.str;
-             free (name->u.init.str);
-             free (name->u2.interop_int);
+             last_init_attr = name->u.init.attr;
+             free (name->u.init.attr);
+             free (name->u2.init_interop_fr);
            }
        }
       else if (free_mapper && name->u2.udm)
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 89d64c36df3a..6567e0269a2e 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -1910,16 +1910,31 @@ error:
    where 'fr' takes an integer named constant or a string literal
    and 'attr takes a string literal, starting with 'ompx_')
 
-Document string + int format
-*/
+   For the foreign runtime identifiers, string values are converted to
+   their integer value; unknown string or integer values are set to 0.
+
+   For the simple syntax, pref_int_array contains alternatingly the
+   fr_id integer value and GOMP_INTEROP_IFR_SEPARATOR followed by a
+   GOMP_INTEROP_IFR_SEPARATOR as last item.
+   For the complex syntax, it contains the values associated with a
+   'fr(...)' followed by GOMP_INTEROP_IFR_SEPARATOR.  If there is no
+   'fr' in a curly-brace block, it is GOMP_INTEROP_IFR_NONE followed
+   by GOMP_INTEROP_IFR_SEPARATOR.  An additional GOMP_INTEROP_IFR_SEPARATOR
+   at the end terminates the array.
+
+   For attributes, if the simply syntax is used, it is NULL - likewise if no
+   'attr' appears.  For the complex syntax it is: For reach curly-brace block,
+   it is \0\0 is no attr appears and otherwise a concatenation (including
+   the \0) of all 'attr' strings followed by a tailing '\0'. At the end,
+   another '\0' follows.  */
 
 static match
-gfc_match_omp_prefer_type (char **pref_str, int *pref_str_len, int 
**pref_int_array)
+gfc_match_omp_prefer_type (char **fr_int_array, char **attr_str, int 
*attr_str_len)
 {
   gfc_expr *e;
-  size_t cnt = 0;
-  std::vector<int> int_list;
-  std::string pref_string;
+  int cnt_brace_grp = 0;
+  std::vector<char> int_list;
+  std::string attr_string;
   /* New syntax.  */
   if (gfc_peek_ascii_char () == '{')
     do
@@ -1929,8 +1944,8 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
            gfc_error ("Expected %<{%> at %C");
            return MATCH_ERROR;
          }
-       std::string attr;
        bool fr_found = false;
+       bool attr_found = false;
        do
          {
            if (gfc_match ("fr ( ") == MATCH_YES)
@@ -1942,99 +1957,129 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
                    return MATCH_ERROR;
                  }
                fr_found = true;
-               gfc_symbol *sym = NULL;
-               e = NULL;
-               locus loc = gfc_current_locus;
-               if (gfc_match_symbol (&sym, 0) != MATCH_YES
-                   || gfc_match (" _") == MATCH_YES)
+               do
                  {
-                   gfc_current_locus = loc;
-                   if (gfc_match_expr (&e) == MATCH_ERROR)
+                   if (gfc_match_expr (&e) != MATCH_YES)
                      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",
-                              &loc);
-                   gfc_free_expr (e);
+                   if (e->expr_type != EXPR_CONSTANT
+                       || e->ref != NULL
+                       || !gfc_resolve_expr (e)
+                       || (e->ts.type != BT_INTEGER
+                           && e->ts.type != BT_CHARACTER)
+                       || (e->ts.type == BT_INTEGER
+                           && (!e->symtree
+                               || e->symtree->n.sym->attr.flavor != 
FL_PARAMETER
+                               || !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 scalar integer parameter or "
+                                  "non-empty default-kind character literal "
+                                  "at %L", &e->where);
+                       gfc_free_expr (e);
+                       return MATCH_ERROR;
+                     }
+                   gfc_gobble_whitespace ();
+                   int val;
+                   if (e->ts.type == BT_INTEGER)
+                     {
+                       val = mpz_get_si (e->value.integer);
+                       if (val < 1 || val > GOMP_INTEROP_IFR_LAST)
+                         {
+                           gfc_warning (OPT_Wopenmp,
+                                        "Unknown foreign runtime identifier "
+                                        "%qd at %L", val, &e->where);
+                           val = 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", &e->where);
+                           return MATCH_ERROR;
+                         }
+                       val = omp_get_fr_id_from_name (str);
+                       if (val == 0)
+                         gfc_warning (OPT_Wopenmp,
+                                      "Unknown foreign runtime identifier %qs "
+                                      "at %L", str, &e->where);
+                     }
+                   int_list.push_back (val);
+                   if (gfc_match (", ") == MATCH_YES)
+                     continue;
+                   if (gfc_match (") ") == MATCH_YES)
+                     break;
+                   gfc_error ("Expected %<,%> or %<)%> at %C");
                    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';
-                 }
+               while (true);
              }
            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)
+               attr_found = true;
+               if (attr_string.empty ())
+                 for (int i = 0; i < cnt_brace_grp; ++i)
+                   {
+                     /* Add dummy elements for previous curly-brace blocks.  */
+                     attr_string += ' ';
+                     attr_string += '\0';
+                     attr_string += '\0';
+                   }
+               do
                  {
-                   gfc_error ("Unexpected null or %<,%> character in "
-                              "character literal at %L", &e->where);
+                   if (gfc_match_expr (&e) != MATCH_YES)
+                     return MATCH_ERROR;
+                   if (e->expr_type != EXPR_CONSTANT
+                       || e->rank != 0
+                       || e->ts.type != BT_CHARACTER
+                   || e->ts.kind != gfc_default_character_kind)
+                     {
+                       gfc_error ("Expected default-kind character literal "
+                                  "at %L", &e->where);
+                       gfc_free_expr (e);
+                       return MATCH_ERROR;
+                     }
+                   gfc_gobble_whitespace ();
+                   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_string += str;
+                   attr_string += '\0';
+                   if (gfc_match (", ") == MATCH_YES)
+                     continue;
+                   if (gfc_match (") ") == MATCH_YES)
+                     break;
+                   gfc_error ("Expected %<,%> or %<)%> at %C");
                    return MATCH_ERROR;
                  }
-               attr += str;
-               attr += '\0';
+               while (true);
              }
            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)
@@ -2043,13 +2088,20 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
            return MATCH_ERROR;
          }
        while (true);
+       ++cnt_brace_grp;
        if (!fr_found)
+         int_list.push_back (GOMP_INTEROP_IFR_NONE);
+       int_list.push_back (GOMP_INTEROP_IFR_SEPARATOR);
+       if (!attr_string.empty ())
          {
-           pref_string += ' ';
-           pref_string += '\0';
+           if (!attr_found)
+             {
+               /* Dummy entry.  */
+               attr_string += ' ';
+               attr_string += '\0';
+             }
+           attr_string += '\0';
          }
-       pref_string += attr;
-       pref_string += '\0';
 
        if (gfc_match (", ") == MATCH_YES)
          continue;
@@ -2065,6 +2117,7 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
        if (gfc_match_expr (&e) != MATCH_YES)
          return MATCH_ERROR;
        if (!gfc_resolve_expr (e)
+           || e->rank != 0
            || e->expr_type != EXPR_CONSTANT
            || (e->ts.type != BT_INTEGER && e->ts.type != BT_CHARACTER)
            || (e->ts.type == BT_INTEGER
@@ -2073,17 +2126,23 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
                && (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_error ("Expected constant scalar integer expression or "
+                      "non-empty default-kind character literal at %L", 
&e->where);
            gfc_free_expr (e);
            return MATCH_ERROR;
          }
+       gfc_gobble_whitespace ();
+       int val;
        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 += ' ';
+           val = mpz_get_si (e->value.integer);
+           if (val < 1 || val > GOMP_INTEROP_IFR_LAST)
+             {
+               gfc_warning (OPT_Wopenmp,
+                            "Unknown foreign runtime identifier %qd at %L",
+                            val, &e->where);
+               val = 0;
+             }
          }
        else
          {
@@ -2092,15 +2151,18 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
              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);
+               gfc_error ("Unexpected null character in character "
+                          "literal at %L", &e->where);
                return MATCH_ERROR;
              }
-           pref_string += str;
+           val = omp_get_fr_id_from_name (str);
+           if (val == 0)
+             gfc_warning (OPT_Wopenmp,
+                          "Unknown foreign runtime identifier %qs at %L",
+                          str, &e->where);
          }
-       pref_string += '\0';
-       pref_string += '\0';
-       ++cnt;
+       int_list.push_back (val);
+       int_list.push_back (GOMP_INTEROP_IFR_SEPARATOR);
        gfc_free_expr (e);
        if (gfc_match (", ") == MATCH_YES)
          continue;
@@ -2110,19 +2172,16 @@ gfc_match_omp_prefer_type (char **pref_str, int 
*pref_str_len, int **pref_int_ar
        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';
+  int_list.push_back (GOMP_INTEROP_IFR_SEPARATOR);
+  *fr_int_array = XNEWVEC (char, int_list.size ());
+  memcpy (*fr_int_array, int_list.data (), sizeof (char) * int_list.size ());
 
-  *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 ())
+  if (!attr_string.empty ())
     {
-      *pref_int_array = XNEWVEC (int, cnt);
-      memcpy (*pref_int_array, int_list.data (), sizeof (int) * cnt);
+      attr_string += '\0';
+      *attr_str_len = attr_string.length();
+      *attr_str = XNEWVEC (char, attr_string.length ());
+      memcpy (*attr_str, attr_string.data (), attr_string.length ());
     }
   return MATCH_YES;
 }
@@ -2135,21 +2194,21 @@ 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;
+  char *fr_int_array = NULL;
+  char *attr_str = NULL;
+  int attr_str_len = 0;
   match m;
   locus old_loc = gfc_current_locus;
   do {
        if (gfc_match ("prefer_type ( ") == MATCH_YES)
        {
-         if (pref_str)
+         if (fr_int_array)
            {
              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);
+         m = gfc_match_omp_prefer_type (&fr_int_array, &attr_str,
+                                        &attr_str_len);
          if (m != MATCH_YES)
            return m;
          if (gfc_match (", ") == MATCH_YES)
@@ -2167,7 +2226,7 @@ gfc_match_omp_init (gfc_omp_namelist **list)
          if (gfc_match (": ") == MATCH_YES)
            break;
          gfc_char_t c = gfc_peek_char ();
-         if (!pref_str
+         if (!fr_int_array
              && (c == ')'
                  || (gfc_current_form != FORM_FREE
                      && (c == '_' || ISALPHA (c)))))
@@ -2186,7 +2245,7 @@ gfc_match_omp_init (gfc_omp_namelist **list)
          if (gfc_match (": ") == MATCH_YES)
            break;
          gfc_char_t c = gfc_peek_char ();
-         if (!pref_str
+         if (!fr_int_array
              && (c == ')'
                  || (gfc_current_form != FORM_FREE
                      && (c == '_' || ISALPHA (c)))))
@@ -2197,7 +2256,7 @@ gfc_match_omp_init (gfc_omp_namelist **list)
          gfc_error ("Expected %<,%> or %<:%> at %C");
          return MATCH_ERROR;
        }
-      if (pref_str)
+      if (fr_int_array)
        {
          gfc_error ("Expected %<target%> or %<targetsync%> at %C");
          return MATCH_ERROR;
@@ -2214,9 +2273,9 @@ gfc_match_omp_init (gfc_omp_namelist **list)
    {
      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;
+     n->u.init.attr = attr_str;
+     n->u.init.len = attr_str_len;
+     n->u2.init_interop_fr = fr_int_array;
    }
  return MATCH_YES;
 }
diff --git a/gcc/omp-api.h b/gcc/omp-api.h
index 0884e51c61cb..1b877f257f09 100644
--- a/gcc/omp-api.h
+++ b/gcc/omp-api.h
@@ -29,4 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 extern bool omp_runtime_api_procname (const char *name);
 extern bool omp_runtime_api_call (const_tree fndecl);
 
+extern int omp_get_fr_id_from_name (const char *);
+extern const char *omp_get_name_from_fr_id (int);
+
 #endif
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index fadea54443db..0b17fda64100 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -3556,6 +3556,35 @@ omp_runtime_api_call (const_tree fndecl)
   return omp_runtime_api_procname (IDENTIFIER_POINTER (declname));
 }
 
+/* See "Additional Definitions for the OpenMP API Specification" document;
+   associated IDs are 1, 2, ...  */
+static const char* omp_interop_fr_str[] = {"cuda", "cuda_driver", "opencl",
+                                          "sycl", "hip", "level_zero", "hsa"};
+
+/* Returns the foreign-runtime ID if found or 0 otherwise.  */
+
+int
+omp_get_fr_id_from_name (const char *str)
+{
+  static_assert (GOMP_INTEROP_IFR_LAST == ARRAY_SIZE (omp_interop_fr_str), "");
+
+  for (unsigned i = 0; i < ARRAY_SIZE (omp_interop_fr_str); ++i)
+    if (!strcmp (str, omp_interop_fr_str[i]))
+      return i + 1;
+  return 0;
+}
+
+/* Returns the string value to a foreign-runtime integer value or NULL if value
+   is not known.  */
+
+const char *
+omp_get_name_from_fr_id (int fr_id)
+{
+  if (fr_id < 1 || fr_id > (int) ARRAY_SIZE (omp_interop_fr_str))
+    return NULL;
+  return omp_interop_fr_str[fr_id-1];
+}
+
 namespace omp_addr_tokenizer {
 
 /* We scan an expression by recursive descent, and build a vector of
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index 0f0bacf153e8..b3f5731d5119 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,13 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-13  Tobias Burnus  <tbur...@baylibre.com>
+
+       PR fortran/116661
+       * gfortran.dg/gomp/interop-1.f90: Extend, update dg-*.
+       * gfortran.dg/gomp/interop-2.f90: Update dg-error.
+       * gfortran.dg/gomp/interop-3.f90: Add dg-warning.
+
 2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
 
        Backported from master:
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-1.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-1.f90
index bbb1dea1be62..8c99fc97f888 100644
--- a/gcc/testsuite/gfortran.dg/gomp/interop-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-1.f90
@@ -28,6 +28,8 @@ implicit none
 
 !$omp requires reverse_offload
 
+integer(omp_interop_fr_kind), parameter :: ifr_array(2) = [omp_ifr_cuda, 
omp_ifr_hip]
+
 integer(omp_interop_kind) :: obj1, obj2, obj3, obj4, obj5
 integer :: x
 
@@ -37,7 +39,7 @@ integer :: x
 !$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 interop init(prefer_type("cu"//char(1)//"da") : obj3)  ! { dg-warning 
"Unknown foreign runtime identifier 'cu\\\\x01da'" }
 !$omp end assume
 
 !$omp interop init(prefer_type("cu"//char(0)//"da") : obj3) ! { dg-error 
"Unexpected null character in character literal" }
@@ -52,11 +54,29 @@ integer :: x
 
 !$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( 4, omp_ifr_hip*4) : obj1)  ! { dg-warning 
"Unknown foreign runtime identifier '20'" }
+!$omp interop init ( prefer_type( sin(3.3) : obj1)  ! { dg-error "Expected 
constant scalar integer expression or non-empty default-kind character literal" 
}
+!$omp interop init ( prefer_type( {fr(4 ) }) : obj1) ! { dg-error "Expected 
scalar integer parameter or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( {fr(4_"cuda" ) }) : obj1) ! { dg-error 
"Expected scalar integer parameter 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
+!$omp interop init ( prefer_type( {fr(1_"cuda" ) }) : obj1) ! OK
+!$omp interop init ( prefer_type( {fr(omp_ifr_level_zero ) }, 
{fr(omp_ifr_hip)}) : obj1) ! OK
+!$omp interop init ( prefer_type( {fr(omp_ifr_level_zero + 1) }) : obj1) ! { 
dg-error "Expected scalar integer parameter or non-empty default-kind character 
literal" }
+!$omp interop init ( prefer_type( {fr(x) }) : obj1) ! { dg-error "Expected 
scalar integer parameter or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( {fr(ifr_array ) }) : obj1) ! { dg-error 
"Expected scalar integer parameter or non-empty default-kind character literal" 
}
+!$omp interop init ( prefer_type( {fr(ifr_array(1) ) }) : obj1) ! { dg-error 
"Expected scalar integer parameter or non-empty default-kind character literal" 
}
+
+!$omp interop init ( prefer_type( omp_ifr_level_zero, omp_ifr_hip ) : obj1) ! 
OK
+!$omp interop init ( prefer_type( omp_ifr_level_zero +1 ) : obj1) ! OK
+!$omp interop init ( prefer_type( x ) : obj1) ! { dg-error "Expected constant 
scalar integer expression or non-empty default-kind character literal" }
+!$omp interop init ( prefer_type( ifr_array ) : obj1) ! { dg-error "Expected 
constant scalar integer expression or non-empty default-kind character literal" 
}
+!$omp interop init ( prefer_type( ifr_array(2) ) : obj1) ! OK
+
+!$omp interop init ( prefer_type( 4, omp_ifr_hip*4) : obj1) ! { dg-warning 
"Unknown foreign runtime identifier '20'" }
+!$omp interop init ( prefer_type( 4, 1, 3) : obj1)
+
+!$omp interop init ( prefer_type( {fr("cuda","sycl") }, 
{fr(omp_ifr_hsa,omp_ifr_level_zero)} , {attr("ompx_a") } , {fr(omp_ifr_hip) }) 
: obj1)
+!$omp interop init ( prefer_type( {fr("cuda","sycl"), attr("ompx_1", 
"ompx_2"), attr("ompx_3") }, {attr("ompx_4", 
"ompx_5"),fr(omp_ifr_hsa,omp_ifr_level_zero)} ) : obj1)
+!$omp interop init ( prefer_type( { fr("cuda","sycl"), attr("ompx_1") }, 
{fr(omp_ifr_hsa,omp_ifr_level_zero)} , {attr("ompx_a") } ) : obj1)
 
 end
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-2.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-2.f90
index c7673a662d0c..f3391bf88f0b 100644
--- a/gcc/testsuite/gfortran.dg/gomp/interop-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-2.f90
@@ -26,7 +26,7 @@ implicit none
 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_"") }) : obj1) ! { dg-error "Expected 
scalar integer parameter 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_'" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/interop-3.f90 
b/gcc/testsuite/gfortran.dg/gomp/interop-3.f90
index a6d2cc460fb0..462ed4f2e4bc 100644
--- a/gcc/testsuite/gfortran.dg/gomp/interop-3.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/interop-3.f90
@@ -33,7 +33,7 @@ integer :: x
 !$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 interop init(prefer_type("cu"//char(1)//"da") : obj3)  ! { dg-warning 
"Unknown foreign runtime identifier 'cu\\\\x01da'" }
 !$omp end assume
 
 !$omp interop init(obj1, obj2, obj1), use(obj4) destroy(obj4)
diff --git a/include/ChangeLog.omp b/include/ChangeLog.omp
index 88098aeb89b2..cb1bc7e6e406 100644
--- a/include/ChangeLog.omp
+++ b/include/ChangeLog.omp
@@ -1,3 +1,12 @@
+2025-01-23  Tobias Burnus  <tbur...@baylibre.com>
+
+       Backported from master:
+       2024-09-13  Tobias Burnus  <tbur...@baylibre.com>
+
+       PR fortran/116661
+       * gomp-constants.h (GOMP_INTEROP_IFR_LAST,
+       GOMP_INTEROP_IFR_SEPARATOR, GOMP_INTEROP_IFR_NONE): New.
+
 2024-05-04  Sandra Loosemore  <sloosem...@baylibre.com>
 
        * cuda/cuda.h (CUdevice_attribute): Add definitions for
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 795c22c97fbb..3266de04e4f0 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -430,6 +430,11 @@ enum gomp_map_kind
 #define GOMP_REQUIRES_REVERSE_OFFLOAD       0x80
 #define GOMP_REQUIRES_TARGET_USED           0x200
 
+/* Interop foreign-runtime data.  */
+#define GOMP_INTEROP_IFR_LAST  7
+#define GOMP_INTEROP_IFR_SEPARATOR -1
+#define GOMP_INTEROP_IFR_NONE -2
+
 /* HSA specific data structures.  */
 
 /* Identifiers of device-specific target arguments.  */

Reply via email to