https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96255

--- Comment #8 from kargl at gcc dot gnu.org ---
New patch.  This adds a bool component to gfc_forall_iterator so
that an iterator with an index-name that shadows a variable from
outer scope can be marked.  Shadowing only occurs when a type-spec
causes the kind type parameter to differ from the kind type 
parameter of the outer scope variable.

A fatal error occurs if shadowing is found.  Someone needs to
wlak the forall block (and by extension the do concurrent block)
updating references to the outer scope variable to be those of
the shadow variable.

It might be beneficial to introduce a namespace for forall and
do concurrent, but I won't go down that path.

Index: gcc/fortran/gfortran.h
===================================================================
--- gcc/fortran/gfortran.h      (revision 280157)
+++ gcc/fortran/gfortran.h      (working copy)
@@ -2525,6 +2525,8 @@ gfc_dt;
 typedef struct gfc_forall_iterator
 {
   gfc_expr *var, *start, *end, *stride;
+  /* index-name shadows a variable from outer scope.  */
+  bool shadow;
   struct gfc_forall_iterator *next;
 }
 gfc_forall_iterator;
Index: gcc/fortran/match.c
===================================================================
--- gcc/fortran/match.c (revision 280157)
+++ gcc/fortran/match.c (working copy)
@@ -2381,7 +2381,10 @@ cleanup:
 }


-/* Match the header of a FORALL statement.  */
+/* Match the header of a FORALL statement.  In F2008 and F2018, the form of
+   the header is 
+   ([ type-spec :: ] concurrent-control-list [, scalar-mask-expr ] )
+   where type-spec is INTEGER.  */

 static match
 match_forall_header (gfc_forall_iterator **phead, gfc_expr **mask)
@@ -2389,6 +2392,9 @@ match_forall_header (gfc_forall_iterator **phead, gfc_
   gfc_forall_iterator *head, *tail, *new_iter;
   gfc_expr *msk;
   match m;
+  gfc_typespec ts;
+  bool seen_ts = false;
+  locus loc;

   gfc_gobble_whitespace ();

@@ -2398,12 +2404,76 @@ match_forall_header (gfc_forall_iterator **phead, gfc_
   if (gfc_match_char ('(') != MATCH_YES)
     return MATCH_NO;

+  /* Check for an optional type-spec.  */
+  gfc_clear_ts (&ts);
+  loc = gfc_current_locus;
+  m = gfc_match_type_spec (&ts);
+  if (m == MATCH_YES)
+    {
+      seen_ts = (gfc_match (" ::") == MATCH_YES);
+
+      if (seen_ts)
+       {
+         if (!gfc_notify_std (GFC_STD_F2008, "FORALL or DO CONCURRENT "
+                              "construct includes type specification "
+                              "at %L", &loc))
+           goto cleanup;
+
+         if (ts.type != BT_INTEGER)
+           {
+             gfc_error ("Type-spec at %L must be an INTEGER type", &loc);
+             goto cleanup;
+           }
+       }
+    }
+  else if (m == MATCH_ERROR)
+    goto syntax;
+
   m = match_forall_iterator (&new_iter);
   if (m == MATCH_ERROR)
     goto cleanup;
   if (m == MATCH_NO)
     goto syntax;

+  if (seen_ts)
+    {
+      char *name;
+      gfc_expr *v;
+      gfc_symtree *st;
+
+      /* If index-name does not have a type and type spec, then update the
+        type spec in both the expr and symtree.  Otherwise, create a new
+        shadow index-name.  */
+      new_iter->shadow = false;
+      v = new_iter->var;
+      if (v->ts.type == BT_UNKNOWN)
+       {
+         v->ts.type = v->symtree->n.sym->ts.type = BT_INTEGER;
+         v->ts.kind = v->symtree->n.sym->ts.kind = ts.kind;
+       }
+      else if (v->ts.kind != ts.kind)
+       {
+         name = (char *) alloca (strlen (v->symtree->name) + 2);
+         strcpy (name, "_");
+         strcat (name, v->symtree->name);
+         if (gfc_get_sym_tree (name, NULL, &st, false) != 0)
+           gfc_internal_error ("whoops");
+
+         v = gfc_get_expr ();
+         v->where = gfc_current_locus;
+         v->expr_type = EXPR_VARIABLE;
+         v->ts.type = st->n.sym->ts.type = ts.type;
+         v->ts.kind = st->n.sym->ts.kind = ts.kind;
+         st->n.sym->forall_index = true;
+         v->symtree = st;
+         gfc_replace_expr (new_iter->var, v);
+         new_iter->shadow = true;
+       }
+      gfc_convert_type (new_iter->start, &ts, 1);
+      gfc_convert_type (new_iter->end, &ts, 1);
+      gfc_convert_type (new_iter->stride, &ts, 1);
+    }
+
   head = tail = new_iter;

   for (;;)
@@ -2417,6 +2487,44 @@ match_forall_header (gfc_forall_iterator **phead, gfc_

       if (m == MATCH_YES)
        {
+         if (seen_ts)
+           {
+             char *name;
+             gfc_expr *v;
+             gfc_symtree *st;
+
+             new_iter->shadow = false;
+             v = new_iter->var;
+             if (v->ts.type == BT_UNKNOWN)
+               {
+                 v->ts.type = v->symtree->n.sym->ts.type = BT_INTEGER;
+                 v->ts.kind = v->symtree->n.sym->ts.kind = ts.kind;
+               }
+             else if (v->ts.kind != ts.kind)
+               {
+                 name = (char *) alloca (strlen (v->symtree->name) + 2);
+                 strcpy (name, "_");
+                 strcat (name, v->symtree->name);
+                 if (gfc_get_sym_tree (name, NULL, &st, false) != 0)
+                   gfc_internal_error ("whoops");
+
+                 v = gfc_get_expr ();
+                 v->expr_type = EXPR_VARIABLE;
+                 v->ts.type = ts.type;
+                 v->ts.kind = ts.kind;
+                 v->where = gfc_current_locus;
+                 st->n.sym->ts.type = ts.type;
+                 st->n.sym->ts.kind = ts.kind;
+                 st->n.sym->forall_index = true;
+                 v->symtree = st;
+                 gfc_replace_expr (new_iter->var, v);
+                 new_iter->shadow = true;
+               }
+             gfc_convert_type (new_iter->start, &ts, 1);
+             gfc_convert_type (new_iter->end, &ts, 1);
+             gfc_convert_type (new_iter->stride, &ts, 1);
+           }
+
          tail->next = new_iter;
          tail = new_iter;
          continue;
Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c       (revision 280157)
+++ gcc/fortran/resolve.c       (working copy)
@@ -10322,11 +10322,10 @@ static void
 gfc_resolve_assign_in_forall (gfc_code *code, int nvar, gfc_expr **var_expr)
 {
   int n;
+  gfc_symbol *forall_index;

   for (n = 0; n < nvar; n++)
     {
-      gfc_symbol *forall_index;
-
       forall_index = var_expr[n]->symtree->n.sym;

       /* Check whether the assignment target is one of the FORALL index
@@ -10475,8 +10474,10 @@ gfc_count_forall_iterators (gfc_code *code)
 }


-/* Given a FORALL construct, first resolve the FORALL iterator, then call
-   gfc_resolve_forall_body to resolve the FORALL body.  */
+/* Given a FORALL construct.
+   1) Resolve the FORALL iterator.
+   2) Check for shadow index-name(s) and update code block.
+   3) call gfc_resolve_forall_body to resolve the FORALL body.  */

 static void
 gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
@@ -10486,6 +10487,7 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns,
   static int nvar = 0;
   int i, old_nvar, tmp;
   gfc_forall_iterator *fa;
+  bool shadow = false;

   old_nvar = nvar;

@@ -10503,8 +10505,9 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns,
       var_expr = XCNEWVEC (gfc_expr *, total_var);
     }

-  /* The information about FORALL iterator, including FORALL indices start,
end
-     and stride.  An outer FORALL indice cannot appear in start, end or
stride.  */
+  /* The information about FORALL iterator, including FORALL indices start,
+     end and stride.  An outer FORALL indice cannot appear in start, end or
+     stride.  Check for a shadow index-name.  */
   for (fa = code->ext.forall_iterator; fa; fa = fa->next)
     {
       /* Fortran 20008: C738 (R753).  */
@@ -10524,6 +10527,9 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns,
                        "with this name %L", &fa->var->where);
        }

+      if (fa->shadow)
+       shadow = true;
+
       /* Record the current FORALL index.  */
       var_expr[nvar] = gfc_copy_expr (fa->var);

@@ -10532,6 +10538,12 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns,
       /* No memory leak.  */
       gcc_assert (nvar <= total_var);
     }
+
+  /* Need to walk the code and replace references to the index-name with
+     references to the shadow index-name.  */
+  if (shadow)
+    gfc_fatal_error ("An index-name shadows a variable from outer scope, "
+                    "which causes a wrong-code bug.");

   /* Resolve the FORALL body.  */
   gfc_resolve_forall_body (code, nvar, var_expr);

Reply via email to