Dear all,

the attached patch fixes a bogus error due to a cyclic dependency that
is found because gfc_traverse_expr also descends into the length type
of character variables.  If the length is determined by the variable
declaration (e.g. assumed-length), it is pre-determined and cannot
be relevant for the dependency check.

(Other brands (e.g. NAG, Intel) all behave as expected.)

The solution is to use the auxiliary parameter of gfc_traverse_expr
to control whether to descend into character length or not.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

Thanks,
Harald

From 4fa9af7adb7a828daf39d822bb8c1244b31c3c1c Mon Sep 17 00:00:00 2001
From: Harald Anlauf <anl...@gmx.de>
Date: Sat, 15 Mar 2025 15:11:22 +0100
Subject: [PATCH] Fortran: fix bogus dependency check in ALLOCATE statement
 [PR60560]

Restrict dependency check of ALLOCATE object to variables in the same
statement, but exclude check of length type parameter that might be
set in the declaration and could lead to a bogus cyclic dependency.

	PR fortran/60560

gcc/fortran/ChangeLog:

	* expr.cc (gfc_traverse_expr): Do not descend into length type
	parameter for negative values of auxiliary parameter f.
	* resolve.cc (gfc_find_var_in_expr): New helper function to check
	dependence of an expression on given variable.
	(resolve_allocate_expr): Use it to determine if array bounds in an
	ALLOCATE statement depend explicitly on a variable.

gcc/testsuite/ChangeLog:

	* gfortran.dg/allocate_error_8.f90: New test.
---
 gcc/fortran/expr.cc                           | 28 +++++++++++--------
 gcc/fortran/resolve.cc                        | 12 ++++++--
 .../gfortran.dg/allocate_error_8.f90          | 17 +++++++++++
 3 files changed, 43 insertions(+), 14 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/allocate_error_8.f90

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 9d84e761576..0753667e061 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -5488,11 +5488,14 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
   if ((*func) (expr, sym, &f))
     return true;
 
-  if (expr->ts.type == BT_CHARACTER
-	&& expr->ts.u.cl
-	&& expr->ts.u.cl->length
-	&& expr->ts.u.cl->length->expr_type != EXPR_CONSTANT
-	&& gfc_traverse_expr (expr->ts.u.cl->length, sym, func, f))
+  /* Descend into length type parameter of character expressions only for
+     non-negative f.  */
+  if (f >= 0
+      && expr->ts.type == BT_CHARACTER
+      && expr->ts.u.cl
+      && expr->ts.u.cl->length
+      && expr->ts.u.cl->length->expr_type != EXPR_CONSTANT
+      && gfc_traverse_expr (expr->ts.u.cl->length, sym, func, f))
     return true;
 
   switch (expr->expr_type)
@@ -5572,13 +5575,14 @@ gfc_traverse_expr (gfc_expr *expr, gfc_symbol *sym,
 	  break;
 
 	case REF_COMPONENT:
-	  if (ref->u.c.component->ts.type == BT_CHARACTER
-		&& ref->u.c.component->ts.u.cl
-		&& ref->u.c.component->ts.u.cl->length
-		&& ref->u.c.component->ts.u.cl->length->expr_type
-		     != EXPR_CONSTANT
-		&& gfc_traverse_expr (ref->u.c.component->ts.u.cl->length,
-				      sym, func, f))
+	  if (f >= 0
+	      && ref->u.c.component->ts.type == BT_CHARACTER
+	      && ref->u.c.component->ts.u.cl
+	      && ref->u.c.component->ts.u.cl->length
+	      && ref->u.c.component->ts.u.cl->length->expr_type
+	      != EXPR_CONSTANT
+	      && gfc_traverse_expr (ref->u.c.component->ts.u.cl->length,
+				    sym, func, f))
 	    return true;
 
 	  if (ref->u.c.component->as)
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 34c8210f66a..d64edff8507 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -8629,6 +8629,14 @@ gfc_find_sym_in_expr (gfc_symbol *sym, gfc_expr *e)
   return gfc_traverse_expr (e, sym, sym_in_expr, 0);
 }
 
+/* Same as gfc_find_sym_in_expr, but do not descend into length type parameter
+   of character expressions.  */
+static bool
+gfc_find_var_in_expr (gfc_symbol *sym, gfc_expr *e)
+{
+  return gfc_traverse_expr (e, sym, sym_in_expr, -1);
+}
+
 
 /* Given the expression node e for an allocatable/pointer of derived type to be
    allocated, get the expression node to be initialized afterwards (needed for
@@ -9190,9 +9198,9 @@ check_symbols:
 	    continue;
 
 	  if ((ar->start[i] != NULL
-	       && gfc_find_sym_in_expr (sym, ar->start[i]))
+	       && gfc_find_var_in_expr (sym, ar->start[i]))
 	      || (ar->end[i] != NULL
-		  && gfc_find_sym_in_expr (sym, ar->end[i])))
+		  && gfc_find_var_in_expr (sym, ar->end[i])))
 	    {
 	      gfc_error ("%qs must not appear in the array specification at "
 			 "%L in the same ALLOCATE statement where it is "
diff --git a/gcc/testsuite/gfortran.dg/allocate_error_8.f90 b/gcc/testsuite/gfortran.dg/allocate_error_8.f90
new file mode 100644
index 00000000000..5637f9fae4d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_error_8.f90
@@ -0,0 +1,17 @@
+! { dg-do compile }
+! PR fortran/60560
+!
+! Original test case by Marco Restelli.
+
+module mstr
+  implicit none
+contains
+  subroutine sub(s)
+    character(len=*),      allocatable, intent(out) :: s(:)
+    character(len=len(s)), allocatable              :: s_tmp(:)
+    allocate(s_tmp(5))
+    allocate(s(size(s_tmp)))          ! OK
+    allocate(s_tmp(5),s(size(s_tmp))) ! { dg-error "same ALLOCATE statement" }
+    allocate(s_tmp(5),s(len(s_tmp)))  ! { dg-error "same ALLOCATE statement" }
+  end subroutine sub
+end module mstr
-- 
2.43.0

Reply via email to