This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: *ping* [patch, fortran] PR 30146, errors for INTENT(OUT) and INTENT(INOUT) for DO loop variables


Hi Steven,

On Sat, Nov 10, 2012 at 3:00 PM, Thomas Koenig wrote:
I wrote:

after the dicsussion on c.l.f, it become clear that passing a DO loop
variable to an INTENT(OUT) or INTENT(INOUT) dummy argument is an error.
The attached patch throws an error for both cases.

But should we really isse an error for INTENT(INOUT)? IMHO a warning suffices, with maybe an error only for strict (i.e. non-GNU) standard settings.

This was the result of a discussion on c.l.f. The summary can be found http://groups.google.com/group/comp.lang.fortran/msg/7107f24b8980fad3?hl=de

Basically, passing an index variable to an INTENT(INOUT) variable
violates a requirement on the program, and than an error would be
the best course of action.

I chose to issue the errors as a front-end pass because we cannot check
for formal arguments during parsing (where the other checks are
implemented).

Regression-tested. OK for trunk?


Ping ** 1.4285 ?

You don't have to list do_list twice in the ChangeLog, you probably wanted one of those to be do_level ;-)

OK.



+ do_list = XNEWVEC(gfc_code *, do_size);

Taste nit: Why not just toss do_list, do_level, and do_size around as a function argument, instead of making them global variable? Just define a struct containing them and pass it around via the "data" argument for gfc_code_walker should work, I think.

The problem is with do_level. This could be incremented in do_warn, but we only know when to decrement it in gfc_code_walker (because there is no EXEC_ENDDO). So, we need a static variable in any case.

The rest is a question of taste. If we need one static variable, I think
we might as well use some other static variables.  The only alternative
I thought about was using a VEC, but frankly the documentation on that
left me baffled as to how to implement this.


IMHO names like "do_warn" and "do_list" are not very descriptive, if
not to say confusing. do_* names are used elsewhere in the compiler
for functions that perform ("do") a task, whereas your do_* functions
are for the Fortran DO construct. I'd prefer different names.

Changed to doloop_*.



+ to an INTENt(OUT) or INTENT(INOUT) dummy variable. */

s/INTENt/INTENT/

Fixed.



+ /* Withot a formal arglist, there is only unknown INTENT,

s/Withot/Without/



+ for (i=0; i<do_level; i++)

for (i = 0; i < do_level; i++)



+ "inside loop beginning at %L as INTENT(OUT) "

Extraneous space after loop.

Fixed.


How do you handle OPTIONAL args?

As far as I have been able to determine, they work:


ig25@linux-fd1f:~/Krempel/Do> cat optional.f90
module opt
  implicit none
contains
  subroutine opt_in(a,b)
  integer, intent(in), optional :: a
  integer, intent(out) :: b
  end subroutine opt_in
end module opt
program main
  use opt
  implicit none
  integer :: i
  do i=1,10
    call opt_in(b=i)
  end do
end program main
ig25@linux-fd1f:~/Krempel/Do> gfortran optional.f90
optional.f90:14.18:

    call opt_in(b=i)
                  1
optional.f90:13.11:

do i=1,10
2
Fehler: Variable 'i' at (1) set to undefined value inside loop beginning at (2) as INTENT(OUT) argument to subroutine 'opt_in'


Or were you thinking of another case?

Attached is the new version of the patch, regression-tested.

Thanks for the review!

OK for trunk?

Thomas

2012-11-11 Thomas Koenig <tkoenig@gcc.gnu.org>

        PR fortran/30146
        * frontend-passes.c (do_warn):  New function.
        (doloop_list):  New static variable.
        (doloop_size):  New static variable.
        (doloop_level):  New static variable.
        (gfc_run_passes): Call doloop_warn.
        (doloop_code):  New function.
        (doloop_function):  New function.
        (gfc_code_walker):  Keep track of DO level.

2012-11-11 Thomas Koenig <tkoenig@gcc.gnu.org>

        PR fortran/30146
        * gfortran.dg/do_check_6.f90:  New test.

Index: frontend-passes.c
===================================================================
--- frontend-passes.c	(Revision 192894)
+++ frontend-passes.c	(Arbeitskopie)
@@ -39,6 +39,7 @@ static bool optimize_trim (gfc_expr *);
 static bool optimize_lexical_comparison (gfc_expr *);
 static void optimize_minmaxloc (gfc_expr **);
 static bool empty_string (gfc_expr *e);
+static void doloop_warn (gfc_namespace *);
 
 /* How deep we are inside an argument list.  */
 
@@ -76,12 +77,30 @@ static bool in_omp_workshare;
 
 static int iterator_level;
 
-/* Entry point - run all passes for a namespace.  So far, only an
-   optimization pass is run.  */
+/* Keep track of DO loop levels.  */
 
+static gfc_code **doloop_list;
+static int doloop_size, doloop_level;
+
+/* Vector of gfc_expr * to keep track of DO loops.  */
+
+struct my_struct *evec;
+
+/* Entry point - run all passes for a namespace. */
+
 void
 gfc_run_passes (gfc_namespace *ns)
 {
+
+  /* Warn about dubious DO loops where the index might
+     change.  */
+
+  doloop_size = 20;
+  doloop_level = 0;
+  doloop_list = XNEWVEC(gfc_code *, doloop_size);
+  doloop_warn (ns);
+  XDELETEVEC (doloop_list);
+
   if (gfc_option.flag_frontend_optimize)
     {
       expr_size = 20;
@@ -1225,6 +1244,160 @@ optimize_minmaxloc (gfc_expr **e)
   mpz_set_ui (a->expr->value.integer, 1);
 }
 
+/* Callback function for code checking that we do not pass a DO variable to an
+   INTENT(OUT) or INTENT(INOUT) dummy variable.  */
+
+static int
+doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
+	 void *data ATTRIBUTE_UNUSED)
+{
+  gfc_code *co;
+  int i;
+  gfc_formal_arglist *f;
+  gfc_actual_arglist *a;
+
+  co = *c;
+
+  switch (co->op)
+    {
+    case EXEC_DO:
+
+      /* Grow the temporary storage if necessary.  */
+      if (doloop_level >= doloop_size)
+	{
+	  doloop_size = 2 * doloop_size;
+	  doloop_list = XRESIZEVEC (gfc_code *, doloop_list, doloop_size);
+	}
+
+      /* Mark the DO loop variable if there is one.  */
+      if (co->ext.iterator && co->ext.iterator->var)
+	doloop_list[doloop_level] = co;
+      else
+	doloop_list[doloop_level] = NULL;
+      break;
+
+    case EXEC_CALL:
+      f = co->symtree->n.sym->formal;
+
+      /* Withot a formal arglist, there is only unknown INTENT,
+	 which we don't check for.  */
+      if (f == NULL)
+	break;
+
+      a = co->ext.actual;
+
+      while (a && f)
+	{
+	  for (i=0; i<doloop_level; i++)
+	    {
+	      gfc_symbol *do_sym;
+	      
+	      if (doloop_list[i] == NULL)
+		break;
+
+	      do_sym = doloop_list[i]->ext.iterator->var->symtree->n.sym;
+	      
+	      if (a->expr && a->expr->symtree
+		  && a->expr->symtree->n.sym == do_sym)
+		{
+		  if (f->sym->attr.intent == INTENT_OUT)
+		    gfc_error_now("Variable '%s' at %L set to undefined value "
+				  "inside loop  beginning at %L as INTENT(OUT) "
+				  "argument to subroutine '%s'", do_sym->name,
+				  &a->expr->where, &doloop_list[i]->loc,
+				  co->symtree->n.sym->name);
+		  else if (f->sym->attr.intent == INTENT_INOUT)
+		    gfc_error_now("Variable '%s' at %L not definable inside loop "
+				  "beginning at %L as INTENT(INOUT) argument to "
+				  "subroutine '%s'", do_sym->name,
+				  &a->expr->where, &doloop_list[i]->loc,
+				  co->symtree->n.sym->name);
+		}
+	    }
+	  a = a->next;
+	  f = f->next;
+	}
+      break;
+
+    default:
+      break;
+    }
+  return 0;
+}
+
+/* Callback function for functions checking that we do not pass a DO variable
+   to an INTENT(OUT) or INTENT(INOUT) dummy variable.  */
+
+static int
+do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+	     void *data ATTRIBUTE_UNUSED)
+{
+  gfc_formal_arglist *f;
+  gfc_actual_arglist *a;
+  gfc_expr *expr;
+  int i;
+
+  expr = *e;
+  if (expr->expr_type != EXPR_FUNCTION)
+    return 0;
+
+  /* Intrinsic functions don't modify their arguments.  */
+
+  if (expr->value.function.isym)
+    return 0;
+
+  f = expr->symtree->n.sym->formal;
+
+  /* Without a formal arglist, there is only unknown INTENT,
+     which we don't check for.  */
+  if (f == NULL)
+    return 0;
+
+  a = expr->value.function.actual;
+
+  while (a && f)
+    {
+      for (i=0; i<doloop_level; i++)
+	{
+	  gfc_symbol *do_sym;
+	 
+    
+	  if (doloop_list[i] == NULL)
+	    break;
+
+	  do_sym = doloop_list[i]->ext.iterator->var->symtree->n.sym;
+	  
+	  if (a->expr && a->expr->symtree
+	      && a->expr->symtree->n.sym == do_sym)
+	    {
+	      if (f->sym->attr.intent == INTENT_OUT)
+		gfc_error_now("Variable '%s' at %L set to undefined value "
+			      "inside loop beginning at %L as INTENT(OUT) "
+			      "argument to function '%s'", do_sym->name,
+			      &a->expr->where, &doloop_list[i]->loc,
+			      expr->symtree->n.sym->name);
+	      else if (f->sym->attr.intent == INTENT_INOUT)
+		gfc_error_now("Variable '%s' at %L not definable inside loop "
+			      "beginning at %L as INTENT(INOUT) argument to "
+			      "function '%s'", do_sym->name,
+			      &a->expr->where, &doloop_list[i]->loc,
+			      expr->symtree->n.sym->name);
+	    }
+	}
+      a = a->next;
+      f = f->next;
+    }
+
+  return 0;
+}
+
+static void
+doloop_warn (gfc_namespace *ns)
+{
+  gfc_code_walker (&ns->code, doloop_code, do_function, NULL);
+}
+
+
 #define WALK_SUBEXPR(NODE) \
   do							\
     {							\
@@ -1383,6 +1556,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t code
 	      break;
 
 	    case EXEC_DO:
+	      doloop_level ++;
 	      WALK_SUBEXPR (co->ext.iterator->var);
 	      WALK_SUBEXPR (co->ext.iterator->start);
 	      WALK_SUBEXPR (co->ext.iterator->end);
@@ -1601,6 +1775,9 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t code
 	  if (co->op == EXEC_FORALL)
 	    forall_level --;
 
+	  if (co->op == EXEC_DO)
+	    doloop_level --;
+
 	  in_omp_workshare = saved_in_omp_workshare;
 	}
     }
! { dg-do compile }
! PR 30146 - warn about DO variables as argument to INTENT(IN) and
! INTENT(INOUT) dummy arguments
program main
  implicit none
  integer :: i,j, k, l
  do k=1,2                      ! { dg-error "undefined value" }
     do i=1,10                  ! { dg-error "definable" }
        do j=1,10               ! { dg-error "undefined value" }
           do l=1,10            ! { dg-error "definable" }
              call s_out(k)      ! { dg-error "undefined" }
              call s_inout(i)    ! { dg-error "definable" }
              print *,f_out(j)   ! { dg-error "undefined" }
              print *,f_inout(l) ! { dg-error "definable" }
           end do
        end do
     end do
  end do
contains
  subroutine s_out(i_arg)
    integer, intent(out) :: i_arg
  end subroutine s_out

  subroutine s_inout(i_arg)
    integer, intent(inout) :: i_arg
  end subroutine s_inout

  function f_out(i_arg)
    integer, intent(out) :: i_arg
    integer :: f_out
    f_out = i_arg
  end function f_out

  function f_inout(i_arg)
    integer, intent(inout) :: i_arg
    integer :: f_inout
    f_inout = i_arg
  end function f_inout

end program main

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]