I will be committing a fix for this to the 16 mainline tonight.

I am requesting Release Manager approval to push to 15 release branch after full testing here.

Regards,

Jerry

See attached diff.

2025-04-18  Steven G. Kargl  <ka...@gcc.gnu.org>

PR fortran/119836
* resolve.cc(check_pure_function, pure_subroutine): Fix checking for
an impure subprogram within a DO CONCURRENT construct.


2025-04-18  Steven G. Kargl  <ka...@gcc.gnu.org>

PR fortran/119836
* gfortran.dg/do_concurrent_all_clauses.f90: Remove invalid
dg-error test.
* gfortran.dg/pr119836_1.f90: New test.
* gfortran.dg/pr119836_2.f90: Ditto.
* gfortran.dg/pr119836_3.f90: Ditto.
* gfortran.dg/pr119836_4.f90: Ditto.
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 2ecbd50fa69..f03708efef7 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -3260,14 +3260,30 @@ static bool check_pure_function (gfc_expr *e)
      gfc_do_concurrent_flag = 0 when the check for an impure function
      occurs.  Check the stack to see if the source code has a nested
      BLOCK construct.  */
+
   for (stack = cs_base; stack; stack = stack->prev)
     {
-      if (stack->current->op == EXEC_BLOCK) saw_block = true;
+      if (!saw_block && stack->current->op == EXEC_BLOCK)
+	{
+	  saw_block = true;
+	  continue;
+	}
+
       if (saw_block && stack->current->op == EXEC_DO_CONCURRENT)
 	{
-	  gfc_error ("Reference to impure function at %L inside a "
-		     "DO CONCURRENT", &e->where);
-	  return false;
+	  bool is_pure;
+	  is_pure = (e->value.function.isym
+		     && (e->value.function.isym->pure
+			 || e->value.function.isym->elemental))
+		    || (e->value.function.esym
+			&& (e->value.function.esym->attr.pure
+			    || e->value.function.esym->attr.elemental));
+	  if (!is_pure)
+	    {
+	      gfc_error ("Reference to impure function at %L inside a "
+			 "DO CONCURRENT", &e->where);
+	      return false;
+	    }
 	}
     }
 
@@ -3663,16 +3679,29 @@ pure_subroutine (gfc_symbol *sym, const char *name, locus *loc)
 
   /* A BLOCK construct within a DO CONCURRENT construct leads to
      gfc_do_concurrent_flag = 0 when the check for an impure subroutine
-     occurs.  Check the stack to see if the source code has a nested
-     BLOCK construct.  */
+     occurs.  Walk up the stack to see if the source code has a nested
+     construct.  */
+
   for (stack = cs_base; stack; stack = stack->prev)
     {
-      if (stack->current->op == EXEC_BLOCK) saw_block = true;
+      if (stack->current->op == EXEC_BLOCK)
+	{
+	  saw_block = true;
+	  continue;
+	}
+
       if (saw_block && stack->current->op == EXEC_DO_CONCURRENT)
 	{
-	  gfc_error ("Subroutine call at %L in a DO CONCURRENT block "
-		     "is not PURE", loc);
-	  return false;
+
+	  bool is_pure = true;
+	  is_pure = sym->attr.pure || sym->attr.elemental;
+
+	  if (!is_pure)
+	    {
+	      gfc_error ("Subroutine call at %L in a DO CONCURRENT block "
+			 "is not PURE", loc);
+	      return false;
+	    }
 	}
     }
 
diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90
index 0c8a6adcabd..a7fa7c31e41 100644
--- a/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90
+++ b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90
@@ -18,7 +18,7 @@ program do_concurrent_all_clauses
       squared = i * i
       arr(i) = temp2 + squared
       sum = sum + arr(i)
-      max_val = max(max_val, arr(i)) ! { dg-error "Reference to impure function" }
+      max_val = max(max_val, arr(i))
     end block
   end do
   print *, arr, sum, max_val
diff --git a/gcc/testsuite/gfortran.dg/pr119836_1.f90 b/gcc/testsuite/gfortran.dg/pr119836_1.f90
new file mode 100644
index 00000000000..984e2d0a73c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr119836_1.f90
@@ -0,0 +1,18 @@
+!
+! { dg-do run }
+!
+! PR fortran/119836
+!
+program p
+   implicit none
+   integer, parameter :: n = 4
+   integer :: i
+   integer :: y(n), x(n)
+   do concurrent (i=1:n)
+      x(i) = shiftl (i,1)     ! accepted
+      block
+         y(i) = shiftl (i,1)  ! wrongly rejected
+      end block
+   end do
+   if (any(x /= y)) stop 1
+end program p
diff --git a/gcc/testsuite/gfortran.dg/pr119836_2.f90 b/gcc/testsuite/gfortran.dg/pr119836_2.f90
new file mode 100644
index 00000000000..5e2d0c9392e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr119836_2.f90
@@ -0,0 +1,21 @@
+!
+! { dg-do compile }
+!
+! PR fortran/119836
+!
+! Although intrinsic functions contained within the Fortran standard
+! are pure procedures, many of the additional intrinsic functions
+! supplied in libgfortran are impure.  RAND() is one such function.
+!
+program foo
+   implicit none
+   integer i
+   real x(4)
+   do concurrent (i=1:4)
+      x = rand()     ! { dg-error "Reference to impure function" }
+      block
+         x = rand()  ! { dg-error "Reference to impure function" }
+      end block
+   end do
+   print *, x
+end program foo
diff --git a/gcc/testsuite/gfortran.dg/pr119836_3.f90 b/gcc/testsuite/gfortran.dg/pr119836_3.f90
new file mode 100644
index 00000000000..69a5fcf7d60
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr119836_3.f90
@@ -0,0 +1,30 @@
+!
+! { dg-do run }
+!
+! PR fortran/119836
+!
+program p
+   implicit none
+   integer, parameter :: n = 4
+   integer :: i
+   integer :: y(n), x(n)
+   x = [(i,i=1,n)]
+   do concurrent (i=1:n)
+      call bar(x, y)
+   end do
+   if (any(x /= y)) stop 1
+   x = 2 * x
+   do concurrent (i=1:n)
+      block
+         call bar(x, y)
+      end block
+   end do
+   if (any(x /= y)) stop 1
+
+   contains
+      elemental subroutine bar(x, y)
+         integer, intent(in) :: x
+         integer, intent(out) :: y
+         y = x
+      end subroutine
+end program p
diff --git a/gcc/testsuite/gfortran.dg/pr119836_4.f90 b/gcc/testsuite/gfortran.dg/pr119836_4.f90
new file mode 100644
index 00000000000..dc6f72b2c99
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr119836_4.f90
@@ -0,0 +1,30 @@
+!
+! { dg-do compile }
+!
+! PR fortran/119836
+!
+program p
+   implicit none
+   integer, parameter :: n = 4
+   integer :: i
+   integer :: y(n), x(n)
+   x = [(i,i=1,n)]
+   do concurrent (i=1:n)
+      call bar(x, y)       ! { dg-error "Subroutine call" }
+   end do
+   if (any(x /= y)) stop 1
+   x = 2 * x
+   do concurrent (i=1:n)
+      block
+         call bar(x, y)    ! { dg-error "Subroutine call" }
+      end block
+   end do
+   if (any(x /= y)) stop 1
+
+   contains
+      subroutine bar(x, y)
+         integer, intent(in) :: x(:)
+         integer, intent(out) :: y(:)
+         y = x
+      end subroutine
+end program p

Reply via email to