https://gcc.gnu.org/g:628859fb41e9f21b9ee048efa5723b1ab4a39a63

commit 628859fb41e9f21b9ee048efa5723b1ab4a39a63
Author: Julian Brown <jul...@codesourcery.com>
Date:   Sat Jul 15 09:16:44 2023 +0000

    OpenMP: Reprocess expanded clauses after 'declare mapper' instantiation
    
    This patch reprocesses expanded clauses after 'declare mapper'
    instantiation -- checking things such as duplicated clauses, illegal
    use of strided accesses, and so forth.  Two functions are broken out
    of the 'resolve_omp_clauses' function and reused in a new function
    'resolve_omp_mapper_clauses', called after mapper instantiation.
    
    This improves diagnostic output.
    
    2023-08-10  Julian Brown  <jul...@codesourcery.com>
    
    gcc/fortran/
            * gfortran.h (gfc_omp_clauses): Add NS field.
            * openmp.cc (verify_omp_clauses_symbol_dups,
            omp_verify_map_motion_clauses): New functions, broken out of...
            (resolve_omp_clauses): Here.  Record namespace containing clauses.
            Call above functions.
            (resolve_omp_mapper_clauses): New function, using helper functions
            broken out above.
            (gfc_resolve_omp_directive): Add NS parameter to resolve_omp_clauses
            calls.
            (gfc_omp_instantiate_mappers): Call resolve_omp_mapper_clauses if we
            instantiate any mappers.
    
    gcc/testsuite/
            * gfortran.dg/gomp/declare-mapper-26.f90: New test.
            * gfortran.dg/gomp/declare-mapper-29.f90: New test.

Diff:
---
 gcc/fortran/ChangeLog.omp                          |   14 +
 gcc/fortran/gfortran.h                             |    1 +
 gcc/fortran/openmp.cc                              | 1123 +++++++++++---------
 gcc/testsuite/ChangeLog.omp                        |    5 +
 .../gfortran.dg/gomp/declare-mapper-26.f90         |   28 +
 .../gfortran.dg/gomp/declare-mapper-29.f90         |   22 +
 6 files changed, 672 insertions(+), 521 deletions(-)

diff --git a/gcc/fortran/ChangeLog.omp b/gcc/fortran/ChangeLog.omp
index 95b3bb90e8f..515a30cd557 100644
--- a/gcc/fortran/ChangeLog.omp
+++ b/gcc/fortran/ChangeLog.omp
@@ -1,3 +1,17 @@
+2023-08-10  Julian Brown  <jul...@codesourcery.com>
+
+       * gfortran.h (gfc_omp_clauses): Add NS field.
+       * openmp.cc (verify_omp_clauses_symbol_dups,
+       omp_verify_map_motion_clauses): New functions, broken out of...
+       (resolve_omp_clauses): Here.  Record namespace containing clauses.
+       Call above functions.
+       (resolve_omp_mapper_clauses): New function, using helper functions
+       broken out above.
+       (gfc_resolve_omp_directive): Add NS parameter to resolve_omp_clauses
+       calls.
+       (gfc_omp_instantiate_mappers): Call resolve_omp_mapper_clauses if we
+       instantiate any mappers.
+
 2023-08-10  Julian Brown  <jul...@codesourcery.com>
 
        * gfortran.h (toc_directive): Move here.
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 3d4abfc6cfd..491a1498279 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1590,6 +1590,7 @@ typedef struct gfc_omp_clauses
   struct gfc_omp_assumptions *assume;
   struct gfc_expr_list *sizes_list;
   const char *critical_name;
+  gfc_namespace *ns;
   enum gfc_omp_default_sharing default_sharing;
   enum gfc_omp_atomic_op atomic_op;
   enum gfc_omp_defaultmap defaultmap[OMP_DEFAULTMAP_CAT_NUM];
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index e7bb4dc80b7..574c1b2ba0c 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -7822,246 +7822,18 @@ gfc_resolve_omp_assumptions (gfc_omp_assumptions 
*assume)
                 &el->expr->where);
 }
 
-
-/* OpenMP directive resolving routines.  */
+/* Check OMP_CLAUSES for duplicate symbols and various other constraints.
+   Helper function for resolve_omp_clauses and resolve_omp_mapper_clauses.  */
 
 static void
-resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
-                    gfc_namespace *ns, bool openacc = false)
+verify_omp_clauses_symbol_dups (gfc_code *code, gfc_omp_clauses *omp_clauses,
+                               gfc_namespace *ns, bool openacc)
 {
-  gfc_omp_namelist *n, *last;
-  gfc_expr_list *el;
+  gfc_omp_namelist *n;
   int list;
-  int ifc;
-  bool if_without_mod = false;
-  gfc_omp_linear_op linear_op = OMP_LINEAR_DEFAULT;
-  static const char *clause_names[]
-    = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED",
-       "COPYIN", "UNIFORM", "AFFINITY", "ALIGNED", "LINEAR", "DEPEND", "MAP",
-       "TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
-       "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
-       "IN_REDUCTION", "TASK_REDUCTION",
-       "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
-       "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
-       "NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
-       "USES_ALLOCATORS" };
-  STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM);
-
-  if (omp_clauses == NULL)
-    return;
-
-  if (ns == NULL)
-    ns = gfc_current_ns;
-
-  if (omp_clauses->orderedc && omp_clauses->orderedc < omp_clauses->collapse)
-    gfc_error ("ORDERED clause parameter is less than COLLAPSE at %L",
-              &code->loc);
-  if (omp_clauses->order_concurrent && omp_clauses->ordered)
-    gfc_error ("ORDER clause must not be used together ORDERED at %L",
-              &code->loc);
-  if (omp_clauses->if_expr)
-    {
-      gfc_expr *expr = omp_clauses->if_expr;
-      if (!gfc_resolve_expr (expr)
-         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
-       gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
-                  &expr->where);
-      if_without_mod = true;
-    }
-  for (ifc = 0; ifc < OMP_IF_LAST; ifc++)
-    if (omp_clauses->if_exprs[ifc])
-      {
-       gfc_expr *expr = omp_clauses->if_exprs[ifc];
-       bool ok = true;
-       if (!gfc_resolve_expr (expr)
-           || expr->ts.type != BT_LOGICAL || expr->rank != 0)
-         gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
-                    &expr->where);
-       else if (if_without_mod)
-         {
-           gfc_error ("IF clause without modifier at %L used together with "
-                      "IF clauses with modifiers",
-                      &omp_clauses->if_expr->where);
-           if_without_mod = false;
-         }
-       else
-         switch (code->op)
-           {
-           case EXEC_OMP_CANCEL:
-             ok = ifc == OMP_IF_CANCEL;
-             break;
-
-           case EXEC_OMP_PARALLEL:
-           case EXEC_OMP_PARALLEL_DO:
-           case EXEC_OMP_PARALLEL_LOOP:
-           case EXEC_OMP_PARALLEL_MASKED:
-           case EXEC_OMP_PARALLEL_MASTER:
-           case EXEC_OMP_PARALLEL_SECTIONS:
-           case EXEC_OMP_PARALLEL_WORKSHARE:
-           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
-           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
-             ok = ifc == OMP_IF_PARALLEL;
-             break;
-
-           case EXEC_OMP_PARALLEL_DO_SIMD:
-           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
-           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
-             ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD;
-             break;
-
-           case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
-           case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
-             ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP;
-             break;
-
-           case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
-           case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
-             ok = (ifc == OMP_IF_PARALLEL
-                   || ifc == OMP_IF_TASKLOOP
-                   || ifc == OMP_IF_SIMD);
-             break;
-
-           case EXEC_OMP_SIMD:
-           case EXEC_OMP_DO_SIMD:
-           case EXEC_OMP_DISTRIBUTE_SIMD:
-           case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD:
-             ok = ifc == OMP_IF_SIMD;
-             break;
-
-           case EXEC_OMP_TASK:
-             ok = ifc == OMP_IF_TASK;
-             break;
-
-           case EXEC_OMP_TASKLOOP:
-           case EXEC_OMP_MASKED_TASKLOOP:
-           case EXEC_OMP_MASTER_TASKLOOP:
-             ok = ifc == OMP_IF_TASKLOOP;
-             break;
-
-           case EXEC_OMP_TASKLOOP_SIMD:
-           case EXEC_OMP_MASKED_TASKLOOP_SIMD:
-           case EXEC_OMP_MASTER_TASKLOOP_SIMD:
-             ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD;
-             break;
-
-           case EXEC_OMP_TARGET:
-           case EXEC_OMP_TARGET_TEAMS:
-           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE:
-           case EXEC_OMP_TARGET_TEAMS_LOOP:
-             ok = ifc == OMP_IF_TARGET;
-             break;
-
-           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
-           case EXEC_OMP_TARGET_SIMD:
-             ok = ifc == OMP_IF_TARGET || ifc == OMP_IF_SIMD;
-             break;
-
-           case EXEC_OMP_TARGET_DATA:
-             ok = ifc == OMP_IF_TARGET_DATA;
-             break;
-
-           case EXEC_OMP_TARGET_UPDATE:
-             ok = ifc == OMP_IF_TARGET_UPDATE;
-             break;
-
-           case EXEC_OMP_TARGET_ENTER_DATA:
-             ok = ifc == OMP_IF_TARGET_ENTER_DATA;
-             break;
-
-           case EXEC_OMP_TARGET_EXIT_DATA:
-             ok = ifc == OMP_IF_TARGET_EXIT_DATA;
-             break;
-
-           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
-           case EXEC_OMP_TARGET_PARALLEL:
-           case EXEC_OMP_TARGET_PARALLEL_DO:
-           case EXEC_OMP_TARGET_PARALLEL_LOOP:
-             ok = ifc == OMP_IF_TARGET || ifc == OMP_IF_PARALLEL;
-             break;
-
-           case EXEC_OMP_TARGET_PARALLEL_DO_SIMD:
-           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
-             ok = (ifc == OMP_IF_TARGET
-                   || ifc == OMP_IF_PARALLEL
-                   || ifc == OMP_IF_SIMD);
-             break;
-
-           default:
-             ok = false;
-             break;
-         }
-       if (!ok)
-         {
-           static const char *ifs[] = {
-             "CANCEL",
-             "PARALLEL",
-             "SIMD",
-             "TASK",
-             "TASKLOOP",
-             "TARGET",
-             "TARGET DATA",
-             "TARGET UPDATE",
-             "TARGET ENTER DATA",
-             "TARGET EXIT DATA"
-           };
-           gfc_error ("IF clause modifier %s at %L not appropriate for "
-                      "the current OpenMP construct", ifs[ifc], &expr->where);
-         }
-      }
-
-  if (omp_clauses->self_expr)
-    {
-      gfc_expr *expr = omp_clauses->self_expr;
-      if (!gfc_resolve_expr (expr)
-         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
-       gfc_error ("SELF clause at %L requires a scalar LOGICAL expression",
-                  &expr->where);
-    }
-
-  if (omp_clauses->final_expr)
-    {
-      gfc_expr *expr = omp_clauses->final_expr;
-      if (!gfc_resolve_expr (expr)
-         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
-       gfc_error ("FINAL clause at %L requires a scalar LOGICAL expression",
-                  &expr->where);
-    }
-  if (omp_clauses->num_threads)
-    resolve_positive_int_expr (omp_clauses->num_threads, "NUM_THREADS");
-  if (omp_clauses->chunk_size)
-    {
-      gfc_expr *expr = omp_clauses->chunk_size;
-      if (!gfc_resolve_expr (expr)
-         || expr->ts.type != BT_INTEGER || expr->rank != 0)
-       gfc_error ("SCHEDULE clause's chunk_size at %L requires "
-                  "a scalar INTEGER expression", &expr->where);
-      else if (expr->expr_type == EXPR_CONSTANT
-              && expr->ts.type == BT_INTEGER
-              && mpz_sgn (expr->value.integer) <= 0)
-       gfc_warning (OPT_Wopenmp, "INTEGER expression of SCHEDULE clause's "
-                    "chunk_size at %L must be positive", &expr->where);
-    }
-  if (omp_clauses->sched_kind != OMP_SCHED_NONE
-      && omp_clauses->sched_nonmonotonic)
-    {
-      if (omp_clauses->sched_monotonic)
-       gfc_error ("Both MONOTONIC and NONMONOTONIC schedule modifiers "
-                  "specified at %L", &code->loc);
-      else if (omp_clauses->ordered)
-       gfc_error ("NONMONOTONIC schedule modifier specified with ORDERED "
-                  "clause at %L", &code->loc);
-    }
 
-  if (omp_clauses->depobj
-      && (!gfc_resolve_expr (omp_clauses->depobj)
-         || omp_clauses->depobj->ts.type != BT_INTEGER
-         || omp_clauses->depobj->ts.kind != 2 * gfc_index_integer_kind
-         || omp_clauses->depobj->rank != 0))
-    gfc_error ("DEPOBJ in DEPOBJ construct at %L shall be a scalar integer "
-              "of OMP_DEPEND_KIND kind", &omp_clauses->depobj->where);
-
-  /* Check that no symbol appears on multiple clauses, except that
-     a symbol can appear on both firstprivate and lastprivate.  */
+  /* Check that no symbol appears on multiple clauses, except that a symbol
+     can appear on both firstprivate and lastprivate.  */
   for (list = 0; list < OMP_LIST_NUM; list++)
     for (n = omp_clauses->lists[list]; n; n = n->next)
       {
@@ -8090,22 +7862,23 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
            && n->sym->result == n->sym
            && n->sym->attr.function)
          {
-           if (ns->proc_name == n->sym
-               || (ns->parent && ns->parent->proc_name == n->sym))
+           if (gfc_current_ns->proc_name == n->sym
+               || (gfc_current_ns->parent
+                   && gfc_current_ns->parent->proc_name == n->sym))
              continue;
-           if (ns->proc_name->attr.entry_master)
+           if (gfc_current_ns->proc_name->attr.entry_master)
              {
-               gfc_entry_list *el = ns->entries;
+               gfc_entry_list *el = gfc_current_ns->entries;
                for (; el; el = el->next)
                  if (el->sym == n->sym)
                    break;
                if (el)
                  continue;
              }
-           if (ns->parent
-               && ns->parent->proc_name->attr.entry_master)
+           if (gfc_current_ns->parent
+               && gfc_current_ns->parent->proc_name->attr.entry_master)
              {
-               gfc_entry_list *el = ns->parent->entries;
+               gfc_entry_list *el = gfc_current_ns->parent->entries;
                for (; el; el = el->next)
                  if (el->sym == n->sym)
                    break;
@@ -8138,8 +7911,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
          && code->op != EXEC_OMP_PARALLEL_DO
          && code->op != EXEC_OMP_PARALLEL_DO_SIMD)
        gfc_error ("%<inscan%> REDUCTION clause on construct other than DO, "
-                  "SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD at %L",
-                  loc);
+                  "SIMD, DO SIMD, PARALLEL DO, PARALLEL DO SIMD at %L", loc);
       if (omp_clauses->ordered)
        gfc_error ("ORDERED clause specified together with %<inscan%> "
                   "REDUCTION clause at %L", loc);
@@ -8233,7 +8005,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
 
   /* Detect specifically the case where we have "map(x) private(x)" and raise
      an error.  If we have "...simd" combined directives though, the "private"
-     applies to the simd part, so this is permitted though.  */
+     applies to the simd part, so this is permitted.  */
   for (n = omp_clauses->lists[OMP_LIST_PRIVATE]; n; n = n->next)
     if (n->sym->mark
        && n->sym->gen_mark
@@ -8243,31 +8015,48 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
        && code->op != EXEC_OMP_TARGET_PARALLEL_DO_SIMD
        && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD
        && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD)
-      gfc_error ("Symbol %qs present on multiple clauses at %L",
-                n->sym->name, &n->where);
+      gfc_error ("Symbol %qs present on multiple clauses at %L", n->sym->name,
+                &n->where);
 
   gcc_assert (OMP_LIST_LASTPRIVATE == OMP_LIST_FIRSTPRIVATE + 1);
   for (list = OMP_LIST_FIRSTPRIVATE; list <= OMP_LIST_LASTPRIVATE; list++)
-    for (n = omp_clauses->lists[list]; n; n = n->next)
-      if (n->sym->data_mark || n->sym->gen_mark || n->sym->dev_mark)
+    {
+      gfc_omp_namelist **pn = &omp_clauses->lists[list];
+      while ((n = *pn) != NULL)
        {
-         gfc_error ("Symbol %qs present on multiple clauses at %L",
-                    n->sym->name, &n->where);
-         n->sym->data_mark = n->sym->gen_mark = n->sym->dev_mark = 0;
-       }
-      else if (n->sym->mark
-              && code->op != EXEC_OMP_TARGET_TEAMS
-              && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE
-              && code->op != EXEC_OMP_TARGET_TEAMS_LOOP
-              && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD
-              && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO
-              && code->op != EXEC_OMP_TARGET_PARALLEL
-              && code->op != EXEC_OMP_TARGET_PARALLEL_DO
-              && code->op != EXEC_OMP_TARGET_PARALLEL_LOOP
-              && code->op != EXEC_OMP_TARGET_PARALLEL_DO_SIMD
-              && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD)
-       gfc_error ("Symbol %qs present on both data and map clauses "
-                  "at %L", n->sym->name, &n->where);
+         bool remove = false;
+
+         if (n->sym->data_mark || n->sym->gen_mark || n->sym->dev_mark)
+           {
+             gfc_error ("Symbol %qs present on multiple clauses at %L",
+                        n->sym->name, &n->where);
+             n->sym->data_mark = n->sym->gen_mark = n->sym->dev_mark = 0;
+           }
+         else if (n->sym->mark
+                  && code->op != EXEC_OMP_TARGET_TEAMS
+                  && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE
+                  && code->op != EXEC_OMP_TARGET_TEAMS_LOOP
+                  && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD
+                  && code->op != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO
+                  && code->op != EXEC_OMP_TARGET_PARALLEL
+                  && code->op != EXEC_OMP_TARGET_PARALLEL_DO
+                  && code->op != EXEC_OMP_TARGET_PARALLEL_LOOP
+                  && code->op != EXEC_OMP_TARGET_PARALLEL_DO_SIMD
+                  && (code->op
+                      != EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD))
+           {
+             gfc_error ("Symbol %qs present on both data and map clauses "
+                        "at %L", n->sym->name, &n->where);
+             /* We've already shown an error.  Avoid confusing gimplify.  */
+             remove = true;
+           }
+
+         if (remove)
+           *pn = n->next;
+         else
+           pn = &n->next;
+       }
+    }
 
   for (n = omp_clauses->lists[OMP_LIST_FIRSTPRIVATE]; n; n = n->next)
     {
@@ -8395,8 +8184,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
          for (n = omp_clauses->lists[OMP_LIST_ALLOCATE]; n; n = n->next)
            if (n->sym->mark == 1)
              gfc_error ("%qs specified in %<allocate%> clause at %L but not "
-                        "in an explicit privatization clause",
-                        n->sym->name, &n->where);
+                        "in an explicit privatization clause", n->sym->name,
+                        &n->where);
        }
       if (code
          && (code->op == EXEC_OMP_ALLOCATORS || code->op == EXEC_OMP_ALLOCATE)
@@ -8518,9 +8307,497 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
                           "must specify an ALLOCATOR clause", &code->loc);
            }
 
-       }
+       }
+    }
+  for (n = omp_clauses->lists[OMP_LIST_TO]; n; n = n->next)
+    n->sym->mark = 0;
+  for (n = omp_clauses->lists[OMP_LIST_FROM]; n; n = n->next)
+    if (n->expr == NULL)
+      n->sym->mark = 1;
+  for (n = omp_clauses->lists[OMP_LIST_TO]; n; n = n->next)
+    {
+      if (n->expr == NULL && n->sym->mark)
+       gfc_error ("Symbol %qs present on both FROM and TO clauses at %L",
+                  n->sym->name, &n->where);
+      else
+       n->sym->mark = 1;
+    }
+}
+
+/* Check that the parameter of a MAP, TO and FROM clause N meets certain
+   constraints.  Helper function for resolve_omp_clauses and
+   resolve_omp_mapper_clauses.  */
+
+static bool
+omp_verify_map_motion_clauses (gfc_code *code, int list, const char *name,
+                              gfc_omp_namelist *n, bool openacc)
+{
+  gfc_ref *lastref = NULL, *lastslice = NULL;
+  bool resolved = false;
+  if (n->expr)
+    {
+      lastref = n->expr->ref;
+      resolved = gfc_resolve_expr (n->expr);
+
+      /* Look through component refs to find last array
+        reference.  */
+      if (resolved)
+       {
+         for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next)
+           if (ref->type == REF_COMPONENT
+               || ref->type == REF_SUBSTRING
+               || ref->type == REF_INQUIRY)
+             lastref = ref;
+           else if (ref->type == REF_ARRAY)
+             {
+               for (int i = 0; i < ref->u.ar.dimen; i++)
+                 if (ref->u.ar.dimen_type[i] == DIMEN_RANGE)
+                   lastslice = ref;
+
+               lastref = ref;
+             }
+
+         /* The "!$acc cache" directive allows rectangular subarrays to be
+            specified, with some restrictions on the form of bounds (not
+            implemented).
+            Only raise an error here if we're really sure the array isn't
+            contiguous.  An expression such as arr(-n:n,-n:n) could be
+            contiguous even if it looks like it may not be.  Also OpenMP's
+            'target update' permits strides for the to/from clause. */
+         if (code
+             && code->op != EXEC_OACC_UPDATE
+             && code->op != EXEC_OMP_TARGET_UPDATE
+             && list != OMP_LIST_CACHE
+             && list != OMP_LIST_DEPEND
+             && !gfc_is_simply_contiguous (n->expr, false, true)
+             && gfc_is_not_contiguous (n->expr)
+             && !(lastslice && (lastslice->next
+                                || lastslice->type != REF_ARRAY)))
+           gfc_error ("Array is not contiguous at %L",
+                      &n->where);
+       }
+    }
+  if (openacc && list == OMP_LIST_MAP
+      && (n->u.map.op == OMP_MAP_ATTACH || n->u.map.op == OMP_MAP_DETACH))
+    {
+      symbol_attribute attr;
+      if (n->expr)
+       attr = gfc_expr_attr (n->expr);
+      else
+       attr = n->sym->attr;
+      if (!attr.pointer && !attr.allocatable)
+       gfc_error ("%qs clause argument must be ALLOCATABLE or a POINTER "
+                  "at %L",
+                  (n->u.map.op == OMP_MAP_ATTACH) ? "attach" : "detach",
+                  &n->where);
+    }
+  if (lastref
+      || (n->expr && (!resolved || n->expr->expr_type != EXPR_VARIABLE)))
+    {
+      if (!lastslice && lastref && lastref->type == REF_SUBSTRING)
+       gfc_error ("Unexpected substring reference in %s clause "
+                  "at %L", name, &n->where);
+      else if (!lastslice && lastref && lastref->type == REF_INQUIRY)
+       {
+         gcc_assert (lastref->u.i == INQUIRY_RE
+                     || lastref->u.i == INQUIRY_IM);
+         gfc_error ("Unexpected complex-parts designator "
+                    "reference in %s clause at %L",
+                    name, &n->where);
+       }
+      else if (!resolved
+              || n->expr->expr_type != EXPR_VARIABLE
+              || (lastslice
+                  && (lastslice->next || lastslice->type != REF_ARRAY)))
+       gfc_error ("%qs in %s clause at %L is not a proper "
+                  "array section", n->sym->name, name,
+                  &n->where);
+      else if (lastslice)
+       {
+         int i;
+         gfc_array_ref *ar = &lastslice->u.ar;
+         for (i = 0; i < ar->dimen; i++)
+           if (ar->stride[i]
+               && code
+               && code->op != EXEC_OACC_UPDATE
+               && code->op != EXEC_OMP_TARGET_UPDATE)
+             {
+               gfc_error ("Stride should not be specified for "
+                          "array section in %s clause at %L",
+                          name, &n->where);
+               return false;
+             }
+           else if (ar->dimen_type[i] != DIMEN_ELEMENT
+                    && ar->dimen_type[i] != DIMEN_RANGE)
+             {
+               gfc_error ("%qs in %s clause at %L is not a "
+                          "proper array section",
+                          n->sym->name, name, &n->where);
+               return false;
+             }
+           else if ((list == OMP_LIST_DEPEND || list == OMP_LIST_AFFINITY)
+                    && ar->start[i]
+                    && ar->start[i]->expr_type == EXPR_CONSTANT
+                    && ar->end[i]
+                    && ar->end[i]->expr_type == EXPR_CONSTANT
+                    && mpz_cmp (ar->start[i]->value.integer,
+                                ar->end[i]->value.integer) > 0)
+             {
+               gfc_error ("%qs in %s clause at %L is a zero size array "
+                          "section", n->sym->name, list == OMP_LIST_DEPEND
+                          ? "DEPEND" : "AFFINITY", &n->where);
+               return false;
+             }
+       }
+    }
+  else if (openacc)
+    {
+      if (list == OMP_LIST_MAP && n->u.map.op == OMP_MAP_FORCE_DEVICEPTR)
+       resolve_oacc_deviceptr_clause (n->sym, n->where, name);
+      else
+       resolve_oacc_data_clauses (n->sym, n->where, name);
+    }
+  else if (list != OMP_LIST_DEPEND
+          && n->sym->as
+          && n->sym->as->type == AS_ASSUMED_SIZE)
+    gfc_error ("Assumed size array %qs in %s clause at %L",
+              n->sym->name, name, &n->where);
+
+  if (!code || list != OMP_LIST_MAP || openacc)
+    return true;
+
+  switch (code->op)
+    {
+    case EXEC_OMP_TARGET:
+    case EXEC_OMP_TARGET_DATA:
+      switch (n->u.map.op)
+       {
+       case OMP_MAP_TO:
+       case OMP_MAP_ALWAYS_TO:
+       case OMP_MAP_PRESENT_TO:
+       case OMP_MAP_ALWAYS_PRESENT_TO:
+       case OMP_MAP_FROM:
+       case OMP_MAP_ALWAYS_FROM:
+       case OMP_MAP_PRESENT_FROM:
+       case OMP_MAP_ALWAYS_PRESENT_FROM:
+       case OMP_MAP_TOFROM:
+       case OMP_MAP_ALWAYS_TOFROM:
+       case OMP_MAP_PRESENT_TOFROM:
+       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+       case OMP_MAP_ALLOC:
+       case OMP_MAP_PRESENT_ALLOC:
+         break;
+       default:
+         gfc_error ("TARGET%s with map-type other than TO, FROM, TOFROM, or "
+                    "ALLOC on MAP clause at %L",
+                    code->op == EXEC_OMP_TARGET ? "" : " DATA", &n->where);
+         break;
+       }
+      break;
+    case EXEC_OMP_TARGET_ENTER_DATA:
+      switch (n->u.map.op)
+       {
+       case OMP_MAP_TO:
+       case OMP_MAP_ALWAYS_TO:
+       case OMP_MAP_PRESENT_TO:
+       case OMP_MAP_ALWAYS_PRESENT_TO:
+       case OMP_MAP_ALLOC:
+       case OMP_MAP_PRESENT_ALLOC:
+         break;
+       case OMP_MAP_TOFROM:
+         n->u.map.op = OMP_MAP_TO;
+         break;
+       case OMP_MAP_ALWAYS_TOFROM:
+         n->u.map.op = OMP_MAP_ALWAYS_TO;
+         break;
+       case OMP_MAP_PRESENT_TOFROM:
+         n->u.map.op = OMP_MAP_PRESENT_TO;
+         break;
+       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+         n->u.map.op = OMP_MAP_ALWAYS_PRESENT_TO;
+         break;
+       default:
+         gfc_error ("TARGET ENTER DATA with map-type other than TO, TOFROM "
+                    "or ALLOC on MAP clause at %L", &n->where);
+         break;
+       }
+      break;
+    case EXEC_OMP_TARGET_EXIT_DATA:
+      switch (n->u.map.op)
+       {
+       case OMP_MAP_FROM:
+       case OMP_MAP_ALWAYS_FROM:
+       case OMP_MAP_PRESENT_FROM:
+       case OMP_MAP_ALWAYS_PRESENT_FROM:
+       case OMP_MAP_RELEASE:
+       case OMP_MAP_DELETE:
+         break;
+       case OMP_MAP_TOFROM:
+         n->u.map.op = OMP_MAP_FROM;
+         break;
+       case OMP_MAP_ALWAYS_TOFROM:
+         n->u.map.op = OMP_MAP_ALWAYS_FROM;
+         break;
+       case OMP_MAP_PRESENT_TOFROM:
+         n->u.map.op = OMP_MAP_PRESENT_FROM;
+         break;
+       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
+         n->u.map.op = OMP_MAP_ALWAYS_PRESENT_FROM;
+         break;
+       default:
+         gfc_error ("TARGET EXIT DATA with map-type other than FROM, TOFROM, "
+                    "RELEASE, or DELETE on MAP clause at %L", &n->where);
+         break;
+       }
+      break;
+    default:
+      ;
+    }
+
+  return true;
+}
+
+/* OpenMP directive resolving routines.  */
+
+static void
+resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
+                    gfc_namespace *ns, bool openacc = false)
+{
+  gfc_omp_namelist *n, *last;
+  gfc_expr_list *el;
+  int list;
+  int ifc;
+  bool if_without_mod = false;
+  gfc_omp_linear_op linear_op = OMP_LINEAR_DEFAULT;
+  static const char *clause_names[]
+    = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED",
+       "COPYIN", "UNIFORM", "AFFINITY", "ALIGNED", "LINEAR", "DEPEND", "MAP",
+       "TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
+       "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
+       "IN_REDUCTION", "TASK_REDUCTION",
+       "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
+       "CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
+       "NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
+       "USES_ALLOCATORS" };
+  STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM);
+
+  if (omp_clauses == NULL)
+    return;
+
+  if (omp_clauses->orderedc && omp_clauses->orderedc < omp_clauses->collapse)
+    gfc_error ("ORDERED clause parameter is less than COLLAPSE at %L",
+              &code->loc);
+  if (omp_clauses->order_concurrent && omp_clauses->ordered)
+    gfc_error ("ORDER clause must not be used together ORDERED at %L",
+              &code->loc);
+  /* If we're invoking any declared mappers as a result of these clauses, we 
may
+     need to know the namespace their directive was originally defined within 
in
+     order to resolve clauses again after substitution.  Record it here.  */
+  if (ns)
+    omp_clauses->ns = ns;
+  if (omp_clauses->if_expr)
+    {
+      gfc_expr *expr = omp_clauses->if_expr;
+      if (!gfc_resolve_expr (expr)
+         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+       gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
+                  &expr->where);
+      if_without_mod = true;
+    }
+  for (ifc = 0; ifc < OMP_IF_LAST; ifc++)
+    if (omp_clauses->if_exprs[ifc])
+      {
+       gfc_expr *expr = omp_clauses->if_exprs[ifc];
+       bool ok = true;
+       if (!gfc_resolve_expr (expr)
+           || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+         gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
+                    &expr->where);
+       else if (if_without_mod)
+         {
+           gfc_error ("IF clause without modifier at %L used together with "
+                      "IF clauses with modifiers",
+                      &omp_clauses->if_expr->where);
+           if_without_mod = false;
+         }
+       else
+         switch (code->op)
+           {
+           case EXEC_OMP_CANCEL:
+             ok = ifc == OMP_IF_CANCEL;
+             break;
+
+           case EXEC_OMP_PARALLEL:
+           case EXEC_OMP_PARALLEL_DO:
+           case EXEC_OMP_PARALLEL_LOOP:
+           case EXEC_OMP_PARALLEL_MASKED:
+           case EXEC_OMP_PARALLEL_MASTER:
+           case EXEC_OMP_PARALLEL_SECTIONS:
+           case EXEC_OMP_PARALLEL_WORKSHARE:
+           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
+             ok = ifc == OMP_IF_PARALLEL;
+             break;
+
+           case EXEC_OMP_PARALLEL_DO_SIMD:
+           case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
+             ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD;
+             break;
+
+           case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+           case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
+             ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP;
+             break;
+
+           case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+           case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+             ok = (ifc == OMP_IF_PARALLEL
+                   || ifc == OMP_IF_TASKLOOP
+                   || ifc == OMP_IF_SIMD);
+             break;
+
+           case EXEC_OMP_SIMD:
+           case EXEC_OMP_DO_SIMD:
+           case EXEC_OMP_DISTRIBUTE_SIMD:
+           case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD:
+             ok = ifc == OMP_IF_SIMD;
+             break;
+
+           case EXEC_OMP_TASK:
+             ok = ifc == OMP_IF_TASK;
+             break;
+
+           case EXEC_OMP_TASKLOOP:
+           case EXEC_OMP_MASKED_TASKLOOP:
+           case EXEC_OMP_MASTER_TASKLOOP:
+             ok = ifc == OMP_IF_TASKLOOP;
+             break;
+
+           case EXEC_OMP_TASKLOOP_SIMD:
+           case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+           case EXEC_OMP_MASTER_TASKLOOP_SIMD:
+             ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD;
+             break;
+
+           case EXEC_OMP_TARGET:
+           case EXEC_OMP_TARGET_TEAMS:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE:
+           case EXEC_OMP_TARGET_TEAMS_LOOP:
+             ok = ifc == OMP_IF_TARGET;
+             break;
+
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
+           case EXEC_OMP_TARGET_SIMD:
+             ok = ifc == OMP_IF_TARGET || ifc == OMP_IF_SIMD;
+             break;
+
+           case EXEC_OMP_TARGET_DATA:
+             ok = ifc == OMP_IF_TARGET_DATA;
+             break;
+
+           case EXEC_OMP_TARGET_UPDATE:
+             ok = ifc == OMP_IF_TARGET_UPDATE;
+             break;
+
+           case EXEC_OMP_TARGET_ENTER_DATA:
+             ok = ifc == OMP_IF_TARGET_ENTER_DATA;
+             break;
+
+           case EXEC_OMP_TARGET_EXIT_DATA:
+             ok = ifc == OMP_IF_TARGET_EXIT_DATA;
+             break;
+
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
+           case EXEC_OMP_TARGET_PARALLEL:
+           case EXEC_OMP_TARGET_PARALLEL_DO:
+           case EXEC_OMP_TARGET_PARALLEL_LOOP:
+             ok = ifc == OMP_IF_TARGET || ifc == OMP_IF_PARALLEL;
+             break;
+
+           case EXEC_OMP_TARGET_PARALLEL_DO_SIMD:
+           case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
+             ok = (ifc == OMP_IF_TARGET
+                   || ifc == OMP_IF_PARALLEL
+                   || ifc == OMP_IF_SIMD);
+             break;
+
+           default:
+             ok = false;
+             break;
+         }
+       if (!ok)
+         {
+           static const char *ifs[] = {
+             "CANCEL",
+             "PARALLEL",
+             "SIMD",
+             "TASK",
+             "TASKLOOP",
+             "TARGET",
+             "TARGET DATA",
+             "TARGET UPDATE",
+             "TARGET ENTER DATA",
+             "TARGET EXIT DATA"
+           };
+           gfc_error ("IF clause modifier %s at %L not appropriate for "
+                      "the current OpenMP construct", ifs[ifc], &expr->where);
+         }
+      }
+
+  if (omp_clauses->self_expr)
+    {
+      gfc_expr *expr = omp_clauses->self_expr;
+      if (!gfc_resolve_expr (expr)
+         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+       gfc_error ("SELF clause at %L requires a scalar LOGICAL expression",
+                  &expr->where);
+    }
+
+  if (omp_clauses->final_expr)
+    {
+      gfc_expr *expr = omp_clauses->final_expr;
+      if (!gfc_resolve_expr (expr)
+         || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+       gfc_error ("FINAL clause at %L requires a scalar LOGICAL expression",
+                  &expr->where);
+    }
+  if (omp_clauses->num_threads)
+    resolve_positive_int_expr (omp_clauses->num_threads, "NUM_THREADS");
+  if (omp_clauses->chunk_size)
+    {
+      gfc_expr *expr = omp_clauses->chunk_size;
+      if (!gfc_resolve_expr (expr)
+         || expr->ts.type != BT_INTEGER || expr->rank != 0)
+       gfc_error ("SCHEDULE clause's chunk_size at %L requires "
+                  "a scalar INTEGER expression", &expr->where);
+      else if (expr->expr_type == EXPR_CONSTANT
+              && expr->ts.type == BT_INTEGER
+              && mpz_sgn (expr->value.integer) <= 0)
+       gfc_warning (0, "INTEGER expression of SCHEDULE clause's chunk_size "
+                    "at %L must be positive", &expr->where);
+    }
+  if (omp_clauses->sched_kind != OMP_SCHED_NONE
+      && omp_clauses->sched_nonmonotonic)
+    {
+      if (omp_clauses->sched_monotonic)
+       gfc_error ("Both MONOTONIC and NONMONOTONIC schedule modifiers "
+                  "specified at %L", &code->loc);
+      else if (omp_clauses->ordered)
+       gfc_error ("NONMONOTONIC schedule modifier specified with ORDERED "
+                  "clause at %L", &code->loc);
     }
 
+  if (omp_clauses->depobj
+      && (!gfc_resolve_expr (omp_clauses->depobj)
+         || omp_clauses->depobj->ts.type != BT_INTEGER
+         || omp_clauses->depobj->ts.kind != 2 * gfc_index_integer_kind
+         || omp_clauses->depobj->rank != 0))
+    gfc_error ("DEPOBJ in DEPOBJ construct at %L shall be a scalar integer "
+              "of OMP_DEPEND_KIND kind", &omp_clauses->depobj->where);
+
+  verify_omp_clauses_symbol_dups (code, omp_clauses, ns, openacc);
+
   /* OpenACC reductions.  */
   if (openacc)
     {
@@ -8542,20 +8819,6 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
        }
     }
   
-  for (n = omp_clauses->lists[OMP_LIST_TO]; n; n = n->next)
-    n->sym->mark = 0;
-  for (n = omp_clauses->lists[OMP_LIST_FROM]; n; n = n->next)
-    if (n->expr == NULL)
-      n->sym->mark = 1;
-  for (n = omp_clauses->lists[OMP_LIST_TO]; n; n = n->next)
-    {
-      if (n->expr == NULL && n->sym->mark)
-       gfc_error ("Symbol %qs present on both FROM and TO clauses at %L",
-                  n->sym->name, &n->where);
-      else
-       n->sym->mark = 1;
-    }
-
   bool has_inscan = false, has_notinscan = false;
   for (list = 0; list < OMP_LIST_NUM; list++)
     if ((n = omp_clauses->lists[list]) != NULL)
@@ -8724,242 +8987,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
                                 "type shall be a scalar integer of "
                                 "OMP_DEPEND_KIND kind", &n->expr->where);
                  }
-               gfc_ref *lastref = NULL, *lastslice = NULL;
-               bool resolved = false;
-               if (n->expr)
-                 {
-                   lastref = n->expr->ref;
-                   resolved = gfc_resolve_expr (n->expr);
-
-                   /* Look through component refs to find last array
-                      reference.  */
-                   if (resolved)
-                     {
-                       for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next)
-                         if (ref->type == REF_COMPONENT
-                             || ref->type == REF_SUBSTRING
-                             || ref->type == REF_INQUIRY)
-                           lastref = ref;
-                         else if (ref->type == REF_ARRAY)
-                           {
-                             for (int i = 0; i < ref->u.ar.dimen; i++)
-                               if (ref->u.ar.dimen_type[i] == DIMEN_RANGE)
-                                 lastslice = ref;
-
-                             lastref = ref;
-                           }
-
-                       /* The "!$acc cache" directive allows rectangular
-                          subarrays to be specified, with some restrictions
-                          on the form of bounds (not implemented).
-                          Only raise an error here if we're really sure the
-                          array isn't contiguous.  An expression such as
-                          arr(-n:n,-n:n) could be contiguous even if it looks
-                          like it may not be.
-                          And OpenMP's 'target update' permits strides for
-                          the to/from clause. */
-                       if (code
-                           && code->op != EXEC_OACC_UPDATE
-                           && code->op != EXEC_OMP_TARGET_UPDATE
-                           && list != OMP_LIST_CACHE
-                           && list != OMP_LIST_DEPEND
-                           && !gfc_is_simply_contiguous (n->expr, false, true)
-                           && gfc_is_not_contiguous (n->expr)
-                           && !(lastslice
-                                && (lastslice->next
-                                    || lastslice->type != REF_ARRAY)))
-                         gfc_error ("Array is not contiguous at %L",
-                                    &n->where);
-                     }
-                 }
-               if (openacc
-                   && list == OMP_LIST_MAP
-                   && (n->u.map.op == OMP_MAP_ATTACH
-                       || n->u.map.op == OMP_MAP_DETACH))
-                 {
-                   symbol_attribute attr;
-                   if (n->expr)
-                     attr = gfc_expr_attr (n->expr);
-                   else
-                     attr = n->sym->attr;
-                   if (!attr.pointer && !attr.allocatable)
-                     gfc_error ("%qs clause argument must be ALLOCATABLE or "
-                                "a POINTER at %L",
-                                (n->u.map.op == OMP_MAP_ATTACH) ? "attach"
-                                : "detach", &n->where);
-                 }
-               if (lastref
-                   || (n->expr
-                       && (!resolved || n->expr->expr_type != EXPR_VARIABLE)))
-                 {
-                   if (!lastslice
-                       && lastref
-                       && lastref->type == REF_SUBSTRING)
-                     gfc_error ("Unexpected substring reference in %s clause "
-                                "at %L", name, &n->where);
-                   else if (!lastslice
-                            && lastref
-                            && lastref->type == REF_INQUIRY)
-                     {
-                       gcc_assert (lastref->u.i == INQUIRY_RE
-                                   || lastref->u.i == INQUIRY_IM);
-                       gfc_error ("Unexpected complex-parts designator "
-                                  "reference in %s clause at %L",
-                                  name, &n->where);
-                     }
-                   else if (!resolved
-                            || n->expr->expr_type != EXPR_VARIABLE
-                            || (lastslice
-                                && (lastslice->next
-                                    || lastslice->type != REF_ARRAY)))
-                     gfc_error ("%qs in %s clause at %L is not a proper "
-                                "array section", n->sym->name, name,
-                                &n->where);
-                   else if (lastslice)
-                     {
-                       int i;
-                       gfc_array_ref *ar = &lastslice->u.ar;
-                       for (i = 0; i < ar->dimen; i++)
-                         if (ar->stride[i]
-                             && code->op != EXEC_OACC_UPDATE
-                             && code->op != EXEC_OMP_TARGET_UPDATE)
-                           {
-                             gfc_error ("Stride should not be specified for "
-                                        "array section in %s clause at %L",
-                                        name, &n->where);
-                             break;
-                           }
-                         else if (ar->dimen_type[i] != DIMEN_ELEMENT
-                                  && ar->dimen_type[i] != DIMEN_RANGE)
-                           {
-                             gfc_error ("%qs in %s clause at %L is not a "
-                                        "proper array section",
-                                        n->sym->name, name, &n->where);
-                             break;
-                           }
-                         else if ((list == OMP_LIST_DEPEND
-                                   || list == OMP_LIST_AFFINITY)
-                                  && ar->start[i]
-                                  && ar->start[i]->expr_type == EXPR_CONSTANT
-                                  && ar->end[i]
-                                  && ar->end[i]->expr_type == EXPR_CONSTANT
-                                  && mpz_cmp (ar->start[i]->value.integer,
-                                              ar->end[i]->value.integer) > 0)
-                           {
-                             gfc_error ("%qs in %s clause at %L is a "
-                                        "zero size array section",
-                                        n->sym->name,
-                                        list == OMP_LIST_DEPEND
-                                        ? "DEPEND" : "AFFINITY", &n->where);
-                             break;
-                           }
-                     }
-                 }
-               else if (openacc)
-                 {
-                   if (list == OMP_LIST_MAP
-                       && n->u.map.op == OMP_MAP_FORCE_DEVICEPTR)
-                     resolve_oacc_deviceptr_clause (n->sym, n->where, name);
-                   else
-                     resolve_oacc_data_clauses (n->sym, n->where, name);
-                 }
-               else if (list != OMP_LIST_DEPEND
-                        && n->sym->as
-                        && n->sym->as->type == AS_ASSUMED_SIZE)
-                 gfc_error ("Assumed size array %qs in %s clause at %L",
-                            n->sym->name, name, &n->where);
-               if (code && list == OMP_LIST_MAP && !openacc)
-                 switch (code->op)
-                   {
-                   case EXEC_OMP_TARGET:
-                   case EXEC_OMP_TARGET_DATA:
-                     switch (n->u.map.op)
-                       {
-                       case OMP_MAP_TO:
-                       case OMP_MAP_ALWAYS_TO:
-                       case OMP_MAP_PRESENT_TO:
-                       case OMP_MAP_ALWAYS_PRESENT_TO:
-                       case OMP_MAP_FROM:
-                       case OMP_MAP_ALWAYS_FROM:
-                       case OMP_MAP_PRESENT_FROM:
-                       case OMP_MAP_ALWAYS_PRESENT_FROM:
-                       case OMP_MAP_TOFROM:
-                       case OMP_MAP_ALWAYS_TOFROM:
-                       case OMP_MAP_PRESENT_TOFROM:
-                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
-                       case OMP_MAP_ALLOC:
-                       case OMP_MAP_PRESENT_ALLOC:
-                         break;
-                       default:
-                         gfc_error ("TARGET%s with map-type other than TO, "
-                                    "FROM, TOFROM, or ALLOC on MAP clause "
-                                    "at %L",
-                                    code->op == EXEC_OMP_TARGET
-                                    ? "" : " DATA", &n->where);
-                         break;
-                       }
-                     break;
-                   case EXEC_OMP_TARGET_ENTER_DATA:
-                     switch (n->u.map.op)
-                       {
-                       case OMP_MAP_TO:
-                       case OMP_MAP_ALWAYS_TO:
-                       case OMP_MAP_PRESENT_TO:
-                       case OMP_MAP_ALWAYS_PRESENT_TO:
-                       case OMP_MAP_ALLOC:
-                       case OMP_MAP_PRESENT_ALLOC:
-                         break;
-                       case OMP_MAP_TOFROM:
-                         n->u.map.op = OMP_MAP_TO;
-                         break;
-                       case OMP_MAP_ALWAYS_TOFROM:
-                         n->u.map.op = OMP_MAP_ALWAYS_TO;
-                         break;
-                       case OMP_MAP_PRESENT_TOFROM:
-                         n->u.map.op = OMP_MAP_PRESENT_TO;
-                         break;
-                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
-                         n->u.map.op = OMP_MAP_ALWAYS_PRESENT_TO;
-                         break;
-                       default:
-                         gfc_error ("TARGET ENTER DATA with map-type other "
-                                    "than TO, TOFROM or ALLOC on MAP clause "
-                                    "at %L", &n->where);
-                         break;
-                       }
-                     break;
-                   case EXEC_OMP_TARGET_EXIT_DATA:
-                     switch (n->u.map.op)
-                       {
-                       case OMP_MAP_FROM:
-                       case OMP_MAP_ALWAYS_FROM:
-                       case OMP_MAP_PRESENT_FROM:
-                       case OMP_MAP_ALWAYS_PRESENT_FROM:
-                       case OMP_MAP_RELEASE:
-                       case OMP_MAP_DELETE:
-                         break;
-                       case OMP_MAP_TOFROM:
-                         n->u.map.op = OMP_MAP_FROM;
-                         break;
-                       case OMP_MAP_ALWAYS_TOFROM:
-                         n->u.map.op = OMP_MAP_ALWAYS_FROM;
-                         break;
-                       case OMP_MAP_PRESENT_TOFROM:
-                         n->u.map.op = OMP_MAP_PRESENT_FROM;
-                         break;
-                       case OMP_MAP_ALWAYS_PRESENT_TOFROM:
-                         n->u.map.op = OMP_MAP_ALWAYS_PRESENT_FROM;
-                         break;
-                       default:
-                         gfc_error ("TARGET EXIT DATA with map-type other "
-                                    "than FROM, TOFROM, RELEASE, or DELETE on "
-                                    "MAP clause at %L", &n->where);
-                         break;
-                       }
-                     break;
-                   default:
-                     break;
-                   }
+               if (!omp_verify_map_motion_clauses (code, list, name, n,
+                                                   openacc))
+                 break;
              }
 
            if (list != OMP_LIST_DEPEND)
@@ -9582,6 +9612,46 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses 
*omp_clauses,
     gfc_resolve_omp_assumptions (omp_clauses->assume);
 }
 
+/* This very simplified version of the above function is for use after mapper
+   instantiation.  It avoids dealing with anything other than basic
+   verification for map/to/from clauses.  */
+
+static void
+resolve_omp_mapper_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
+                           gfc_namespace *ns)
+{
+  gfc_omp_namelist *n;
+  int list;
+
+  verify_omp_clauses_symbol_dups (code, omp_clauses, ns, false);
+
+  for (list = OMP_LIST_MAP; list <= OMP_LIST_FROM; list++)
+    if ((n = omp_clauses->lists[list]) != NULL)
+      {
+       const char *name = NULL;
+       switch (list)
+         {
+         case OMP_LIST_MAP:
+           if (name == NULL)
+             name = "MAP";
+           /* Fallthrough.  */
+         case OMP_LIST_TO:
+           if (name == NULL)
+             name = "TO";
+           /* Fallthrough.  */
+         case OMP_LIST_FROM:
+           if (name == NULL)
+             name = "FROM";
+           for (; n != NULL; n = n->next)
+             if (!omp_verify_map_motion_clauses (code, list, name, n, false))
+               break;
+           break;
+         default:
+           ;
+         }
+      }
+}
+
 
 /* Return true if SYM is ever referenced in EXPR except in the SE node.  */
 
@@ -12084,11 +12154,11 @@ gfc_resolve_omp_directive (gfc_code *code, 
gfc_namespace *ns)
     case EXEC_OMP_WORKSHARE:
     case EXEC_OMP_DEPOBJ:
       if (code->ext.omp_clauses)
-       resolve_omp_clauses (code, code->ext.omp_clauses, NULL);
+       resolve_omp_clauses (code, code->ext.omp_clauses, ns);
       break;
     case EXEC_OMP_TARGET_UPDATE:
       if (code->ext.omp_clauses)
-       resolve_omp_clauses (code, code->ext.omp_clauses, NULL);
+       resolve_omp_clauses (code, code->ext.omp_clauses, ns);
       if (code->ext.omp_clauses == NULL
          || (code->ext.omp_clauses->lists[OMP_LIST_TO] == NULL
              && code->ext.omp_clauses->lists[OMP_LIST_FROM] == NULL))
@@ -12689,6 +12759,7 @@ gfc_omp_instantiate_mappers (gfc_code *code, 
gfc_omp_clauses *clauses,
 {
   gfc_omp_namelist *clause = clauses->lists[list];
   gfc_omp_namelist **clausep = &clauses->lists[list];
+  bool invoked_mappers = false;
 
   for (; clause; clause = *clausep)
     {
@@ -12715,10 +12786,20 @@ gfc_omp_instantiate_mappers (gfc_code *code, 
gfc_omp_clauses *clauses,
          clausep = gfc_omp_instantiate_mapper (clausep, clause, outer_map_op,
                                                clause->u2.udm->udm, cd, list);
          *clausep = clause->next;
+         invoked_mappers = true;
        }
       else
        clausep = &clause->next;
     }
+
+  if (invoked_mappers)
+    {
+      gfc_namespace *old_ns = gfc_current_ns;
+      if (clauses->ns)
+       gfc_current_ns = clauses->ns;
+      resolve_omp_mapper_clauses (code, clauses, gfc_current_ns);
+      gfc_current_ns = old_ns;
+    }
 }
 
 /* Resolve !$omp declare mapper constructs.  */
diff --git a/gcc/testsuite/ChangeLog.omp b/gcc/testsuite/ChangeLog.omp
index e4c8afd0293..49ea82ac86b 100644
--- a/gcc/testsuite/ChangeLog.omp
+++ b/gcc/testsuite/ChangeLog.omp
@@ -1,3 +1,8 @@
+2023-08-10  Julian Brown  <jul...@codesourcery.com>
+
+       * gfortran.dg/gomp/declare-mapper-26.f90: New test.
+       * gfortran.dg/gomp/declare-mapper-29.f90: New test.
+
 2023-07-14  Julian Brown  <jul...@codesourcery.com>
 
        * c-c++-common/gomp/declare-mapper-3.c: Enable for C.
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90 
b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90
new file mode 100644
index 00000000000..c408b37f5a9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90
@@ -0,0 +1,28 @@
+! { dg-do compile }
+
+type t
+integer, allocatable :: arr(:)
+end type t
+
+!$omp declare mapper(even: T :: tv) map(tv%arr(2::2))
+
+type(t) :: var
+
+allocate(var%arr(100))
+
+var%arr = 0
+
+! You can't do this, the mapper specifies a noncontiguous access.
+!$omp target enter data map(mapper(even), to: var)
+! { dg-error {Stride should not be specified for array section in MAP clause} 
"" { target *-*-* } .-1 }
+
+var%arr = 1
+
+! But this is fine.  (Re-enabled by later patch.)
+!!$omp target update to(mapper(even): var)
+
+! As 'enter data'.
+!$omp target exit data map(mapper(even), delete: var)
+! { dg-error {Stride should not be specified for array section in MAP clause} 
"" { target *-*-* } .-1 }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-29.f90 
b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-29.f90
new file mode 100644
index 00000000000..e2039e80e57
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-29.f90
@@ -0,0 +1,22 @@
+! { dg-do compile }
+
+! Check duplicate clause detection after mapper expansion.
+
+type t
+integer :: x
+end type t
+
+real(4) :: unrelated
+type(t) :: tvar
+
+!$omp declare mapper (t :: var) map(unrelated) map(var%x)
+
+tvar%x = 0
+unrelated = 5
+
+!$omp target firstprivate(unrelated) map(tofrom: tvar)
+! { dg-error "Symbol .unrelated. present on both data and map clauses" "" { 
target *-*-* } .-1 }
+tvar%x = unrelated
+!$omp end target
+
+end

Reply via email to