See the attached patch.
I finally had some time to get back to this one.
Regression tested ob x86_64.
OK for mainline?
Regards,
Jerry
---
fortran: namelist read with repeat count fails when member of array
When processing a namelist with a repeat count and the object is a
component of a derived type, we need to go through the components
and update each one.
PR fortran/82086
libgfortran/ChangeLog:
* io/list_read.c (nml_read_obj): Add is_component parameter
to correctly distribute repeat count across derived-type array
elements.
gcc/testsuite/ChangeLog:
* gfortran.dg/namelist_103.f90: New test.
commit 00ff4597ff7626f80a5c2a556fc1b8b0f8ae835d
Author: Jerry DeLisle <[email protected]>
Date: Fri Jun 19 18:37:52 2026 -0700
fortran: namelist read with repeat count fails when member of array
When processing a namelist with a repeat count and the object is a
component of a derived type, we need to go through the components
and update each one.
PR fortran/82086
libgfortran/ChangeLog:
* io/list_read.c (nml_read_obj): Add is_component parameter
to correctly distribute repeat count across derived-type array
elements.
gcc/testsuite/ChangeLog:
* gfortran.dg/namelist_103.f90: New test.
diff --git a/gcc/testsuite/gfortran.dg/namelist_103.f90 b/gcc/testsuite/gfortran.dg/namelist_103.f90
new file mode 100644
index 00000000000..18ecb11ee51
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/namelist_103.f90
@@ -0,0 +1,27 @@
+! { dg-do run }
+! PR fortran/82086 - namelist read of derived-type array component
+! with a repeat count must set all addressed elements.
+program pr82086
+ implicit none
+ type t
+ character(64) :: c = ''
+ end type t
+ type(t), dimension(16) :: ta
+ integer :: i
+ namelist /n/ ta
+
+ open (10, status="scratch", delim="apostrophe")
+ write (10, '(a)') "&n"
+ write (10, '(a)') " ta(1:8)%c = 8*'bogus'"
+ write (10, '(a)') "/"
+ rewind (10)
+ read (10, nml=n)
+ close (10)
+
+ do i = 1, 8
+ if (ta(i)%c /= 'bogus') stop i
+ end do
+ do i = 9, 16
+ if (ta(i)%c /= '') stop 10+i
+ end do
+end program pr82086
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index 7b71cf38719..757f2faac23 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -2652,7 +2652,8 @@ calls:
static void nml_touch_nodes (namelist_info *nl)
static int nml_read_obj (namelist_info *nl, index_type offset,
namelist_info **prev_nl, char *, size_t,
- index_type clow, index_type chigh)
+ index_type clow, index_type chigh,
+ bool is_component)
calls:
-itself- */
@@ -3123,7 +3124,8 @@ query_return:
static bool
nml_read_obj (st_parameter_dt *dtp, namelist_info *nl, index_type offset,
namelist_info **pprev_nl, char *nml_err_msg,
- size_t nml_err_msg_size, index_type clow, index_type chigh)
+ size_t nml_err_msg_size, index_type clow, index_type chigh,
+ bool is_component)
{
namelist_info *cmp;
char *obj_name;
@@ -3142,7 +3144,8 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info *nl, index_type offset,
return true;
dtp->u.p.item_count++; /* Used in error messages. */
- dtp->u.p.repeat_count = 0;
+ if (!is_component)
+ dtp->u.p.repeat_count = 0;
eat_spaces (dtp);
len = nl->len;
@@ -3196,9 +3199,60 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info *nl, index_type offset,
* GFC_DESCRIPTOR_STRIDE(nl,dim) * nl->size);
}
+ nml_carry = 0;
+
+ /* A default (non-DTIO) derived type does not itself hold a value to
+ read; only its components do. Recurse into the components on
+ every iteration of the array loop, independently of the repeat
+ count, so that a repeat count parsed while reading one component
+ (e.g. "ta(1:8)%c = 8*'bogus'") gets applied to that component for
+ each addressed array element. */
+
+ if ((nl->type == BT_DERIVED || nl->type == BT_CLASS)
+ && nl->dtio_sub == NULL)
+ {
+ obj_name_len = strlen (nl->var_name) + 1;
+ obj_name = xmalloc (obj_name_len+1);
+ memcpy (obj_name, nl->var_name, obj_name_len-1);
+ memcpy (obj_name + obj_name_len - 1, "%", 2);
+
+ /* If reading a derived type, disable the expanded read warning
+ since a single object can have multiple reads. */
+ dtp->u.p.expanded_read = 0;
+
+ /* Now loop over the components. */
+
+ for (cmp = nl->next;
+ cmp &&
+ !strncmp (cmp->var_name, obj_name, obj_name_len);
+ cmp = cmp->next)
+ {
+ /* Jump over nested derived type by testing if the potential
+ component name contains '%'. */
+ if (strchr (cmp->var_name + obj_name_len, '%'))
+ continue;
+
+ if (!nml_read_obj (dtp, cmp, (index_type)(pdata - nl->mem_pos),
+ pprev_nl, nml_err_msg, nml_err_msg_size,
+ clow, chigh, true))
+ {
+ free (obj_name);
+ return false;
+ }
+
+ if (dtp->u.p.input_complete)
+ {
+ free (obj_name);
+ return true;
+ }
+ }
+
+ free (obj_name);
+ goto incr_idx;
+ }
+
/* If we are finished with the repeat count, try to read next value. */
- nml_carry = 0;
if (--dtp->u.p.repeat_count <= 0)
{
if (dtp->u.p.input_complete)
@@ -3241,8 +3295,8 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info *nl, index_type offset,
case BT_DERIVED:
case BT_CLASS:
- /* If this object has a User Defined procedure, call it. */
- if (nl->dtio_sub != NULL)
+ /* This object has a User Defined I/O procedure; objects
+ without one were already handled above. */
{
GFC_INTEGER_4 unit = dtp->u.p.current_unit->unit_number;
char iotype[] = "NAMELIST";
@@ -3302,46 +3356,6 @@ nml_read_obj (st_parameter_dt *dtp, namelist_info *nl, index_type offset,
goto incr_idx;
}
- /* Must be default derived type namelist read. */
- obj_name_len = strlen (nl->var_name) + 1;
- obj_name = xmalloc (obj_name_len+1);
- memcpy (obj_name, nl->var_name, obj_name_len-1);
- memcpy (obj_name + obj_name_len - 1, "%", 2);
-
- /* If reading a derived type, disable the expanded read warning
- since a single object can have multiple reads. */
- dtp->u.p.expanded_read = 0;
-
- /* Now loop over the components. */
-
- for (cmp = nl->next;
- cmp &&
- !strncmp (cmp->var_name, obj_name, obj_name_len);
- cmp = cmp->next)
- {
- /* Jump over nested derived type by testing if the potential
- component name contains '%'. */
- if (strchr (cmp->var_name + obj_name_len, '%'))
- continue;
-
- if (!nml_read_obj (dtp, cmp, (index_type)(pdata - nl->mem_pos),
- pprev_nl, nml_err_msg, nml_err_msg_size,
- clow, chigh))
- {
- free (obj_name);
- return false;
- }
-
- if (dtp->u.p.input_complete)
- {
- free (obj_name);
- return true;
- }
- }
-
- free (obj_name);
- goto incr_idx;
-
default:
snprintf (nml_err_msg, nml_err_msg_size,
"Bad type for namelist object %s", nl->var_name);
@@ -3456,7 +3470,7 @@ incr_idx:
}
} while (!nml_carry);
- if (dtp->u.p.repeat_count > 1)
+ if (!is_component && dtp->u.p.repeat_count > 1)
{
snprintf (nml_err_msg, nml_err_msg_size,
"Repeat count too large for namelist object %s", nl->var_name);
@@ -3780,7 +3794,7 @@ get_name:
dtp->u.p.nml_read_error = 0;
if (!nml_read_obj (dtp, nl, 0, pprev_nl, nml_err_msg, nml_err_msg_size,
- clow, chigh))
+ clow, chigh, false))
goto nml_err_ret;
return true;