From a3d3c0f5fa9cd88e6285f60c593cb753cc53d4c2 Mon Sep 17 00:00:00 2001
From: Daniel Kraft <d@domob.eu>
Date: Thu, 9 Oct 2008 09:28:22 +0200
Subject: [PATCH] re PR fortran/35723 (Can't use run-time array element in
 character declaration)

2008-10-09  Daniel Kraft  <d@domob.eu>

	PR fortran/35723
	* gfortran.h (gfc_suppress_error): Removed from header.
	(gfc_push_suppress_errors), (gfc_pop_suppress_errors): New methods.
	* array.c (gfc_array_size): Use new gfc_push/pop_suppress_errors
	instead of directly changing gfc_suppress_error.
	* intrinsic.c (gfc_intrinsic_func_interface): Ditto.
	(gfc_intrinsic_sub_interface): Ditto.
	* error.c (suppress_errors): Made static from `gfc_suppress_error'.
	(gfc_push_suppress_errors), (gfc_pop_suppress_errors): New methods.
	(gfc_notify_std), (gfc_error): Use new static name of global.
	* expr.c (check_arglist), (check_references): New methods.
	(check_restricted): Check arglists and references of EXPR_FUNCTIONs
	and EXPR_VARAIBALEs, respectively.  Allow PARAMETER symbols.

2008-10-09  Daniel Kraft  <d@domob.eu>

	PR fortran/35723
	* gfortran.dg/restricted_expression_1.f90: New test.
	* gfortran.dg/restricted_expression_2.f90: New test.
	* gfortran.dg/restricted_expression_3.f90: New test.

From-SVN: r141001
---
 gcc/fortran/ChangeLog                         | 16 ++++
 gcc/fortran/array.c                           |  8 +-
 gcc/fortran/error.c                           | 26 +++++-
 gcc/fortran/expr.c                            | 83 ++++++++++++++++++-
 gcc/fortran/gfortran.h                        |  5 +-
 gcc/fortran/intrinsic.c                       | 40 ++++++---
 gcc/testsuite/ChangeLog                       |  7 ++
 .../gfortran.dg/restricted_expression_1.f90   | 25 ++++++
 .../gfortran.dg/restricted_expression_2.f90   | 25 ++++++
 .../gfortran.dg/restricted_expression_3.f90   | 26 ++++++
 10 files changed, 238 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/restricted_expression_1.f90
 create mode 100644 gcc/testsuite/gfortran.dg/restricted_expression_2.f90
 create mode 100644 gcc/testsuite/gfortran.dg/restricted_expression_3.f90

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index b0ef1cef8be5..a2ca844018c0 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,19 @@
+2008-10-09  Daniel Kraft  <d@domob.eu>
+
+	PR fortran/35723
+	* gfortran.h (gfc_suppress_error): Removed from header.
+	(gfc_push_suppress_errors), (gfc_pop_suppress_errors): New methods.
+	* array.c (gfc_array_size): Use new gfc_push/pop_suppress_errors
+	instead of directly changing gfc_suppress_error.
+	* intrinsic.c (gfc_intrinsic_func_interface): Ditto.
+	(gfc_intrinsic_sub_interface): Ditto.
+	* error.c (suppress_errors): Made static from `gfc_suppress_error'.
+	(gfc_push_suppress_errors), (gfc_pop_suppress_errors): New methods.
+	(gfc_notify_std), (gfc_error): Use new static name of global.
+	* expr.c (check_arglist), (check_references): New methods.
+	(check_restricted): Check arglists and references of EXPR_FUNCTIONs
+	and EXPR_VARAIBALEs, respectively.  Allow PARAMETER symbols.
+
 2008-10-07  Jakub Jelinek  <jakub@redhat.com>
 
 	* f95-lang.c (poplevel): Don't clear BLOCK_VARS if functionbody.
diff --git a/gcc/fortran/array.c b/gcc/fortran/array.c
index d99ed9e30a06..70cf66294da8 100644
--- a/gcc/fortran/array.c
+++ b/gcc/fortran/array.c
@@ -2073,14 +2073,13 @@ gfc_array_size (gfc_expr *array, mpz_t *result)
 {
   expand_info expand_save;
   gfc_ref *ref;
-  int i, flag;
+  int i;
   gfc_try t;
 
   switch (array->expr_type)
     {
     case EXPR_ARRAY:
-      flag = gfc_suppress_error;
-      gfc_suppress_error = 1;
+      gfc_push_suppress_errors ();
 
       expand_save = current_expand;
 
@@ -2091,7 +2090,8 @@ gfc_array_size (gfc_expr *array, mpz_t *result)
       iter_stack = NULL;
 
       t = expand_constructor (array->value.constructor);
-      gfc_suppress_error = flag;
+
+      gfc_pop_suppress_errors ();
 
       if (t == FAILURE)
 	mpz_clear (*result);
diff --git a/gcc/fortran/error.c b/gcc/fortran/error.c
index 7a5fbd347111..a7005e9fbb61 100644
--- a/gcc/fortran/error.c
+++ b/gcc/fortran/error.c
@@ -30,13 +30,33 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "gfortran.h"
 
-int gfc_suppress_error = 0;
+static int suppress_errors = 0;
 
 static int terminal_width, buffer_flag, errors, warnings;
 
 static gfc_error_buf error_buffer, warning_buffer, *cur_error_buffer;
 
 
+/* Go one level deeper suppressing errors.  */
+
+void
+gfc_push_suppress_errors (void)
+{
+  gcc_assert (suppress_errors >= 0);
+  ++suppress_errors;
+}
+
+
+/* Leave one level of error suppressing.  */
+
+void
+gfc_pop_suppress_errors (void)
+{
+  gcc_assert (suppress_errors > 0);
+  --suppress_errors;
+}
+
+
 /* Per-file error initialization.  */
 
 void
@@ -764,7 +784,7 @@ gfc_notify_std (int std, const char *nocmsgid, ...)
   if ((gfc_option.allow_std & std) != 0 && !warning)
     return SUCCESS;
 
-  if (gfc_suppress_error)
+  if (suppress_errors)
     return warning ? SUCCESS : FAILURE;
 
   cur_error_buffer = warning ? &warning_buffer : &error_buffer;
@@ -850,7 +870,7 @@ gfc_error (const char *nocmsgid, ...)
 {
   va_list argp;
 
-  if (gfc_suppress_error)
+  if (suppress_errors)
     return;
 
   error_buffer.flag = 1;
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 7f6bf1b07e47..5a167b7067f8 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -2503,6 +2503,64 @@ restricted_intrinsic (gfc_expr *e)
 }
 
 
+/* Check the expressions of an actual arglist.  Used by check_restricted.  */
+
+static gfc_try
+check_arglist (gfc_actual_arglist* arg, gfc_try (*checker) (gfc_expr*))
+{
+  for (; arg; arg = arg->next)
+    if (checker (arg->expr) == FAILURE)
+      return FAILURE;
+
+  return SUCCESS;
+}
+
+
+/* Check the subscription expressions of a reference chain with a checking
+   function; used by check_restricted.  */
+
+static gfc_try
+check_references (gfc_ref* ref, gfc_try (*checker) (gfc_expr*))
+{
+  int dim;
+
+  if (!ref)
+    return SUCCESS;
+
+  switch (ref->type)
+    {
+    case REF_ARRAY:
+      for (dim = 0; dim != ref->u.ar.dimen; ++dim)
+	{
+	  if (checker (ref->u.ar.start[dim]) == FAILURE)
+	    return FAILURE;
+	  if (checker (ref->u.ar.end[dim]) == FAILURE)
+	    return FAILURE;
+	  if (checker (ref->u.ar.stride[dim]) == FAILURE)
+	    return FAILURE;
+	}
+      break;
+
+    case REF_COMPONENT:
+      /* Nothing needed, just proceed to next reference.  */
+      break;
+
+    case REF_SUBSTRING:
+      if (checker (ref->u.ss.start) == FAILURE)
+	return FAILURE;
+      if (checker (ref->u.ss.end) == FAILURE)
+	return FAILURE;
+      break;
+
+    default:
+      gcc_unreachable ();
+      break;
+    }
+
+  return check_references (ref->next, checker);
+}
+
+
 /* Verify that an expression is a restricted expression.  Like its
    cousin check_init_expr(), an error message is generated if we
    return FAILURE.  */
@@ -2510,7 +2568,7 @@ restricted_intrinsic (gfc_expr *e)
 static gfc_try
 check_restricted (gfc_expr *e)
 {
-  gfc_symbol *sym;
+  gfc_symbol* sym;
   gfc_try t;
 
   if (e == NULL)
@@ -2526,8 +2584,22 @@ check_restricted (gfc_expr *e)
       break;
 
     case EXPR_FUNCTION:
-      t = e->value.function.esym ? external_spec_function (e)
-				 : restricted_intrinsic (e);
+      if (e->value.function.esym)
+	{
+	  t = check_arglist (e->value.function.actual, &check_restricted);
+	  if (t == SUCCESS)
+	    t = external_spec_function (e);
+	}
+      else
+	{
+	  if (e->value.function.isym && e->value.function.isym->inquiry)
+	    t = SUCCESS;
+	  else
+	    t = check_arglist (e->value.function.actual, &check_restricted);
+
+	  if (t == SUCCESS)
+	    t = restricted_intrinsic (e);
+	}
       break;
 
     case EXPR_VARIABLE:
@@ -2561,6 +2633,10 @@ check_restricted (gfc_expr *e)
 	  break;
 	}
 
+      /* Check reference chain if any.  */
+      if (check_references (e->ref, &check_restricted) == FAILURE)
+	break;
+
       /* gfc_is_formal_arg broadcasts that a formal argument list is being
 	 processed in resolve.c(resolve_formal_arglist).  This is done so
 	 that host associated dummy array indices are accepted (PR23446).
@@ -2571,6 +2647,7 @@ check_restricted (gfc_expr *e)
 	    || sym->attr.use_assoc
 	    || sym->attr.dummy
 	    || sym->attr.implied_index
+	    || sym->attr.flavor == FL_PARAMETER
 	    || (sym->ns && sym->ns == gfc_current_ns->parent)
 	    || (sym->ns && gfc_current_ns->parent
 		  && sym->ns == gfc_current_ns->parent->parent)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index b032486abfd5..42f5516b746b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -770,7 +770,10 @@ typedef struct
 #endif
 
 
-extern int gfc_suppress_error;
+/* Suppress error messages or re-enable them.  */
+
+void gfc_push_suppress_errors (void);
+void gfc_pop_suppress_errors (void);
 
 
 /* Character length structures hold the expression that gives the
diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c
index 035aef70d659..7acdcb05e608 100644
--- a/gcc/fortran/intrinsic.c
+++ b/gcc/fortran/intrinsic.c
@@ -3598,7 +3598,8 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
     return (do_simplify (expr->value.function.isym, expr) == FAILURE)
 	   ? MATCH_ERROR : MATCH_YES;
 
-  gfc_suppress_error = !error_flag;
+  if (!error_flag)
+    gfc_push_suppress_errors ();
   flag = 0;
 
   for (actual = expr->value.function.actual; actual; actual = actual->next)
@@ -3611,7 +3612,8 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
   isym = specific = gfc_find_function (name);
   if (isym == NULL)
     {
-      gfc_suppress_error = 0;
+      if (!error_flag)
+	gfc_pop_suppress_errors ();
       return MATCH_NO;
     }
 
@@ -3621,7 +3623,11 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
       && gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Function '%s' "
 			 "as initialization expression at %L", name,
 			 &expr->where) == FAILURE)
-    return MATCH_ERROR;
+    {
+      if (!error_flag)
+	gfc_pop_suppress_errors ();
+      return MATCH_ERROR;
+    }
 
   gfc_current_intrinsic_where = &expr->where;
 
@@ -3633,7 +3639,8 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
       if (gfc_check_min_max (expr->value.function.actual) == SUCCESS)
 	goto got_specific;
 
-      gfc_suppress_error = 0;
+      if (!error_flag)
+	gfc_pop_suppress_errors ();
       return MATCH_NO;
     }
 
@@ -3641,7 +3648,7 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
      incarnations.  If the generic name is also a specific, we check
      that name last, so that any error message will correspond to the
      specific.  */
-  gfc_suppress_error = 1;
+  gfc_push_suppress_errors ();
 
   if (isym->generic)
     {
@@ -3651,15 +3658,19 @@ gfc_intrinsic_func_interface (gfc_expr *expr, int error_flag)
 	  if (specific == isym)
 	    continue;
 	  if (check_specific (specific, expr, 0) == SUCCESS)
-	    goto got_specific;
+	    {
+	      gfc_pop_suppress_errors ();
+	      goto got_specific;
+	    }
 	}
     }
 
-  gfc_suppress_error = !error_flag;
+  gfc_pop_suppress_errors ();
 
   if (check_specific (isym, expr, error_flag) == FAILURE)
     {
-      gfc_suppress_error = 0;
+      if (!error_flag)
+	gfc_pop_suppress_errors ();
       return MATCH_NO;
     }
 
@@ -3669,7 +3680,9 @@ got_specific:
   expr->value.function.isym = specific;
   gfc_intrinsic_symbol (expr->symtree->n.sym);
 
-  gfc_suppress_error = 0;
+  if (!error_flag)
+    gfc_pop_suppress_errors ();
+
   if (do_simplify (specific, expr) == FAILURE)
     return MATCH_ERROR;
 
@@ -3709,7 +3722,8 @@ gfc_intrinsic_sub_interface (gfc_code *c, int error_flag)
   if (isym == NULL)
     return MATCH_NO;
 
-  gfc_suppress_error = !error_flag;
+  if (!error_flag)
+    gfc_push_suppress_errors ();
 
   init_arglist (isym);
 
@@ -3729,7 +3743,8 @@ gfc_intrinsic_sub_interface (gfc_code *c, int error_flag)
 
   /* The subroutine corresponds to an intrinsic.  Allow errors to be
      seen at this point.  */
-  gfc_suppress_error = 0;
+  if (!error_flag)
+    gfc_pop_suppress_errors ();
 
   if (isym->resolve.s1 != NULL)
     isym->resolve.s1 (c);
@@ -3751,7 +3766,8 @@ gfc_intrinsic_sub_interface (gfc_code *c, int error_flag)
   return MATCH_YES;
 
 fail:
-  gfc_suppress_error = 0;
+  if (!error_flag)
+    gfc_pop_suppress_errors ();
   return MATCH_NO;
 }
 
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8ea5a241cb09..2e61e8ca8a49 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2008-10-09  Daniel Kraft  <d@domob.eu>
+
+	PR fortran/35723
+	* gfortran.dg/restricted_expression_1.f90: New test.
+	* gfortran.dg/restricted_expression_2.f90: New test.
+	* gfortran.dg/restricted_expression_3.f90: New test.
+
 2008-10-08  Jerry DeLisle  <jvdelisle@gcc.gnu.org
 
 	PR libfortran/37707
diff --git a/gcc/testsuite/gfortran.dg/restricted_expression_1.f90 b/gcc/testsuite/gfortran.dg/restricted_expression_1.f90
new file mode 100644
index 000000000000..45211a585f40
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/restricted_expression_1.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+! { dg-options "-pedantic -ffixed-form" }
+
+! PR fortran/35723
+! An argument subscript into a parameter array was not allowed as
+! dimension.  Check this is fixed.
+
+! Contributed by Dick Hendrickson <dick.hendrickson@gmail.com>
+
+      call       vf0016(  1,  2,  3)
+
+      end
+      SUBROUTINE VF0016(nf1,nf2,nf3)
+      CHARACTER(LEN=9,KIND=1),DIMENSION(3), PARAMETER
+     $     ::  TEST_STRINGS =
+     $  (/'       HI','ABC      ','  CDEFG  '/)
+      CHARACTER :: TEST_ARRAY
+     $(LEN_TRIM(ADJUSTL(TEST_STRINGS(nf1))),
+     $ SUM(LEN_TRIM(ADJUSTL(TEST_STRINGS))),
+     $ LEN_TRIM(ADJUSTL(ADJUSTR(TEST_STRINGS(3)))),
+     $ SUM(LEN_TRIM(ADJUSTL(ADJUSTR(TEST_STRINGS(NF1:NF3:NF2)))))   )
+
+       print *, 2, 10, 5, 7
+       print *, shape (test_array)
+         end
diff --git a/gcc/testsuite/gfortran.dg/restricted_expression_2.f90 b/gcc/testsuite/gfortran.dg/restricted_expression_2.f90
new file mode 100644
index 000000000000..9c281664a841
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/restricted_expression_2.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+! { dg-options "-pedantic -ffixed-form" }
+
+! PR fortran/35723
+! Check that a program using a local variable subscript is still rejected.
+
+! Contributed by Tobias Burnus <burnus@gcc.gnu.org>
+
+      call       vf0016(  1,  2,  3)
+
+      end
+      SUBROUTINE VF0016(nf1,nf2,nf3)
+      CHARACTER(LEN=9,KIND=1),DIMENSION(3), PARAMETER
+     $     ::  TEST_STRINGS =
+     $  (/'       HI','ABC      ','  CDEFG  '/)
+      INTEGER :: i = 2
+      CHARACTER :: TEST_ARRAY
+     $(LEN_TRIM(ADJUSTL(TEST_STRINGS(i))), ! { dg-error "'i' cannot appear" }
+     $ SUM(LEN_TRIM(ADJUSTL(TEST_STRINGS))),
+     $ LEN_TRIM(ADJUSTL(ADJUSTR(TEST_STRINGS(3)))),
+     $ SUM(LEN_TRIM(ADJUSTL(ADJUSTR(TEST_STRINGS(NF1:NF3:NF2)))))   )
+
+       print *, 2, 10, 5, 7
+       print *, shape (test_array)
+         end
diff --git a/gcc/testsuite/gfortran.dg/restricted_expression_3.f90 b/gcc/testsuite/gfortran.dg/restricted_expression_3.f90
new file mode 100644
index 000000000000..0b84f67aa588
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/restricted_expression_3.f90
@@ -0,0 +1,26 @@
+! { dg-do compile }
+
+! PR fortran/35723
+! Check that a dummy-argument array with non-restricted subscript is
+! rejected and some more reference-checks.
+
+PROGRAM main
+  IMPLICIT NONE
+  CALL test (5, (/ 1, 2, 3, 4, 5, 6, 7, 8, 9 /), "0123456789" )
+
+CONTAINS
+
+  SUBROUTINE test (n, arr, str)
+    IMPLICIT NONE
+    INTEGER :: n, arr(:)
+    CHARACTER(len=10) :: str
+
+    INTEGER :: i = 5
+    INTEGER :: ok1(arr(n)), ok2(LEN_TRIM (str(3:n)))
+    INTEGER :: ok3(LEN_TRIM("hello, world!"(2:n)))
+    INTEGER :: wrong1(arr(i)) ! { dg-error "'i' cannot appear" }
+    INTEGER :: wrong2(LEN_TRIM (str(i:n))) ! { dg-error "'i' cannot appear" }
+    INTEGER :: wrong3(LEN_TRIM ("hello, world!"(i:n))) ! { dg-error "'i' cannot appear" }
+  END SUBROUTINE test
+
+END PROGRAM main
-- 
GitLab