See the attached patch.

This takes care of the STAT= problem identified here:

https://gcc.gnu.org/pipermail/fortran/2026-September/064686.html

Regression tested on x86_64.

OK for mainline?

Regards,

Jerry

---

 libgfortran: [PR127347] caf_shmem: report a terminated image
 in a collective

A collective subroutine whose barrier was abandoned because an image of
the team terminated reported this with a runtime error, and so
terminated the remaining images even when a STAT argument was present.

F2023 16.6 assigns STAT_STOPPED_IMAGE, or STAT_FAILED_IMAGE, to the
STAT argument in that case and leaves the A argument undefined; an
error condition without a STAT argument still is error termination.
Pass the abandoned barrier up to the collective and classify it the
same way an image control statement does.

        PR libfortran/127347

libgfortran/ChangeLog:

        * caf/shmem.c (_gfortran_caf_co_broadcast, _gfortran_caf_co_sum)
        (_gfortran_caf_co_min, _gfortran_caf_co_max)
        (_gfortran_caf_co_reduce): Report a terminated image of the team
        through STAT.
        * caf/shmem/collective_subroutine.c (collsub_sync): Return whether
        the images were synchronized.
        (collsub_reduce_array, collsub_broadcast_array): Likewise.  Give up
        when an image of the team terminated.
        * caf/shmem/collective_subroutine.h (collsub_reduce_array)
        (collsub_broadcast_array): Adjust.

gcc/testsuite/ChangeLog:

        * gfortran.dg/coarray/collective_stopped_2.f90: New test.
---
From a09c79a2beb519398cce5c56e66f328fd813003e Mon Sep 17 00:00:00 2001
From: Jerry DeLisle <[email protected]>
Date: Thu, 24 Sep 2026 12:39:51 -0700
Subject: [PATCH] libgfortran: [PR127347] caf_shmem: report a terminated image
 in a collective

A collective subroutine whose barrier was abandoned because an image of
the team terminated reported this with a runtime error, and so
terminated the remaining images even when a STAT argument was present.

F2023 16.6 assigns STAT_STOPPED_IMAGE, or STAT_FAILED_IMAGE, to the
STAT argument in that case and leaves the A argument undefined; an
error condition without a STAT argument still is error termination.
Pass the abandoned barrier up to the collective and classify it the
same way an image control statement does.

	PR libfortran/127347

libgfortran/ChangeLog:

	* caf/shmem.c (_gfortran_caf_co_broadcast, _gfortran_caf_co_sum)
	(_gfortran_caf_co_min, _gfortran_caf_co_max)
	(_gfortran_caf_co_reduce): Report a terminated image of the team
	through STAT.
	* caf/shmem/collective_subroutine.c (collsub_sync): Return whether
	the images were synchronized.
	(collsub_reduce_array, collsub_broadcast_array): Likewise.  Give up
	when an image of the team terminated.
	* caf/shmem/collective_subroutine.h (collsub_reduce_array)
	(collsub_broadcast_array): Adjust.

gcc/testsuite/ChangeLog:

	* gfortran.dg/coarray/collective_stopped_2.f90: New test.
---
 .../coarray/collective_stopped_2.f90          | 32 ++++++++++++++++
 libgfortran/caf/shmem.c                       | 16 +++++---
 libgfortran/caf/shmem/collective_subroutine.c | 37 ++++++++++---------
 libgfortran/caf/shmem/collective_subroutine.h |  7 +++-
 4 files changed, 68 insertions(+), 24 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/coarray/collective_stopped_2.f90

diff --git a/gcc/testsuite/gfortran.dg/coarray/collective_stopped_2.f90 b/gcc/testsuite/gfortran.dg/coarray/collective_stopped_2.f90
new file mode 100644
index 00000000000..2a4e4f3207e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/coarray/collective_stopped_2.f90
@@ -0,0 +1,32 @@
+! { dg-do run }
+!
+! An image terminating while the others are inside a collective subroutine
+! has to be reported through stat=, not by terminating them.
+
+program collective_stopped_2
+  use iso_fortran_env, only : stat_stopped_image
+  implicit none
+  integer :: s[*]
+  integer :: st, img
+
+  if (num_images () == 1) stop
+  img = max (num_images () / 2, 2)
+  s = this_image ()
+  if (this_image () == img) then
+    call spin ()
+    stop
+  end if
+
+  st = 0
+  call co_sum (s, stat=st)
+  if (st /= stat_stopped_image) stop 1
+contains
+  subroutine spin ()
+    integer :: c
+    integer(kind=8) :: v
+    v = 2
+    do c = 1, 20000000
+      v = mod (v * 2, 1999619_8)
+    end do
+  end subroutine
+end program collective_stopped_2
diff --git a/libgfortran/caf/shmem.c b/libgfortran/caf/shmem.c
index 00d851ab539..aacb1fd6f86 100644
--- a/libgfortran/caf/shmem.c
+++ b/libgfortran/caf/shmem.c
@@ -859,7 +859,9 @@ _gfortran_caf_co_broadcast (gfc_descriptor_t *desc, int source_image, int *stat,
 		       NULL, stat))
     return;
 
-  collsub_broadcast_array (desc, mapped_index);
+  /* A terminated image leaves the collective incomplete (F2023 16.6).  */
+  if (!collsub_broadcast_array (desc, mapped_index))
+    HEALTH_CHECK (stat, errmsg, errmsg_len);
 }
 
 #define GEN_OP(name, op, type)                                                 \
@@ -961,7 +963,8 @@ _gfortran_caf_co_sum (gfc_descriptor_t *desc, int result_image, int *stat,
 
   SWITCH_TYPE_KIND (sum)
 
-  collsub_reduce_array (desc, mapped_index, opr, 0, 0);
+  if (!collsub_reduce_array (desc, mapped_index, opr, 0, 0))
+    HEALTH_CHECK (stat, errmsg, errmsg_len);
 }
 
 void
@@ -986,7 +989,8 @@ _gfortran_caf_co_min (gfc_descriptor_t *desc, int result_image, int *stat,
 
   SWITCH_TYPE_KIND (min)
 
-  collsub_reduce_array (desc, mapped_index, opr, 0, 0);
+  if (!collsub_reduce_array (desc, mapped_index, opr, 0, 0))
+    HEALTH_CHECK (stat, errmsg, errmsg_len);
 }
 
 void
@@ -1011,7 +1015,8 @@ _gfortran_caf_co_max (gfc_descriptor_t *desc, int result_image, int *stat,
 
   SWITCH_TYPE_KIND (max)
 
-  collsub_reduce_array (desc, mapped_index, opr, 0, 0);
+  if (!collsub_reduce_array (desc, mapped_index, opr, 0, 0))
+    HEALTH_CHECK (stat, errmsg, errmsg_len);
 }
 
 void
@@ -1034,7 +1039,8 @@ _gfortran_caf_co_reduce (gfc_descriptor_t *desc, void *(*opr) (void *, void *),
 			  NULL, stat))
     return;
 
-  collsub_reduce_array (desc, mapped_index, opr, opr_flags, desc_len);
+  if (!collsub_reduce_array (desc, mapped_index, opr, opr_flags, desc_len))
+    HEALTH_CHECK (stat, errmsg, errmsg_len);
 }
 
 void
diff --git a/libgfortran/caf/shmem/collective_subroutine.c b/libgfortran/caf/shmem/collective_subroutine.c
index f97789cab1c..911c54acbee 100644
--- a/libgfortran/caf/shmem/collective_subroutine.c
+++ b/libgfortran/caf/shmem/collective_subroutine.c
@@ -22,7 +22,6 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
-#include "../caf_error.h"
 #include "collective_subroutine.h"
 #include "supervisor.h"
 #include "teams_mgmt.h"
@@ -221,16 +220,15 @@ get_collsub_buf (size_t size)
 
 /* This function syncs all images with one another.  It will only return once
    all images have called it.  The reduction is laid out over a fixed set of
-   images, so it cannot be completed once an image of the team terminated.  */
+   images, so it cannot be completed once an image of the team terminated.
+   Returns false in that case.  */
 
-static void
+static bool
 collsub_sync (void)
 {
   counter_barrier *barrier = &caf_current_team->u.image_info->collsub.barrier;
 
-  if (!counter_barrier_wait_abortable (barrier))
-    caf_runtime_error ("Image terminated while executing a collective "
-		       "subroutine");
+  return counter_barrier_wait_abortable (barrier);
 }
 
 typedef void *(*red_op) (void *, void *);
@@ -321,7 +319,7 @@ gen_reduction (const int type, const size_t sz, const int flags)
 
 /* Having result_image == -1 means allreduce.  */
 
-void
+bool
 collsub_reduce_array (gfc_descriptor_t *desc, int result_image,
 		      void *(*op) (void *, void *), int opr_flags,
 		      int str_len __attribute__ ((unused)))
@@ -339,7 +337,7 @@ collsub_reduce_array (gfc_descriptor_t *desc, int result_image,
 
   packed = pack_array_prepare (&pi, desc);
   if (pi.num_elem == 0)
-    return;
+    return true;
 
   elem_size = GFC_DESCRIPTOR_SIZE (desc);
   this_image_size_bytes = elem_size * pi.num_elem;
@@ -354,7 +352,8 @@ collsub_reduce_array (gfc_descriptor_t *desc, int result_image,
     pack_array_finish (&pi, desc, this_image_buf);
 
   assign = gen_reduction (GFC_DESCRIPTOR_TYPE (desc), elem_size, opr_flags);
-  collsub_sync ();
+  if (!collsub_sync ())
+    return false;
 
   for (; ((this_img_id >> cbit) & 1) == 0
 	 && (caf_current_team->u.image_info->image_count.count >> cbit) != 0;
@@ -371,11 +370,13 @@ collsub_reduce_array (gfc_descriptor_t *desc, int result_image,
 	       ++i, roll_iter += elem_size, src_iter += elem_size)
 	    assign (op, roll_iter, src_iter, elem_size);
 	}
-      collsub_sync ();
+      if (!collsub_sync ())
+	return false;
     }
   for (; (caf_current_team->u.image_info->image_count.count >> cbit) != 0;
        cbit++)
-    collsub_sync ();
+    if (!collsub_sync ())
+      return false;
 
   if (result_image < 0 || result_image == this_image.image_num)
     {
@@ -385,14 +386,14 @@ collsub_reduce_array (gfc_descriptor_t *desc, int result_image,
 	unpack_array_finish (&pi, desc, buffer);
     }
 
-  collsub_sync ();
+  return collsub_sync ();
 }
 
 /* Do not use sync_all(), because the program should deadlock in the case that
  * some images are on a sync_all barrier while others are in a collective
  * subroutine.  */
 
-void
+bool
 collsub_broadcast_array (gfc_descriptor_t *desc, int source_image)
 {
   void *buffer;
@@ -403,7 +404,7 @@ collsub_broadcast_array (gfc_descriptor_t *desc, int source_image)
 
   packed = pack_array_prepare (&pi, desc);
   if (pi.num_elem == 0)
-    return;
+    return true;
 
   if (GFC_DESCRIPTOR_TYPE (desc) == BT_CHARACTER)
     {
@@ -423,16 +424,18 @@ collsub_broadcast_array (gfc_descriptor_t *desc, int source_image)
 	memcpy (buffer, GFC_DESCRIPTOR_DATA (desc), size_bytes);
       else
 	pack_array_finish (&pi, desc, buffer);
-      collsub_sync ();
+      if (!collsub_sync ())
+	return false;
     }
   else
     {
-      collsub_sync ();
+      if (!collsub_sync ())
+	return false;
       if (packed)
 	memcpy (GFC_DESCRIPTOR_DATA (desc), buffer, size_bytes);
       else
 	unpack_array_finish (&pi, desc, buffer);
     }
 
-  collsub_sync ();
+  return collsub_sync ();
 }
diff --git a/libgfortran/caf/shmem/collective_subroutine.h b/libgfortran/caf/shmem/collective_subroutine.h
index 76b1610f976..01ad34adf5f 100644
--- a/libgfortran/caf/shmem/collective_subroutine.h
+++ b/libgfortran/caf/shmem/collective_subroutine.h
@@ -42,9 +42,12 @@ typedef struct collsub_shared
 void collsub_init_supervisor (collsub_shared *, allocator *,
 			      const int init_num_images);
 
-void collsub_broadcast_array (gfc_descriptor_t *, int);
+/* Both return false when an image of the current team terminated before the
+   collective could be completed.  */
 
-void collsub_reduce_array (gfc_descriptor_t *, int, void *(*) (void *, void *),
+bool collsub_broadcast_array (gfc_descriptor_t *, int);
+
+bool collsub_reduce_array (gfc_descriptor_t *, int, void *(*) (void *, void *),
 			   int opr_flags, int str_len);
 
 #endif
-- 
2.55.0

Reply via email to