Hi all, I intend to commit the attached patch for a problem with derived-type I/O and namelist output by tomorrow, if there are no objections. The dtio_25.f90 test case needed some adjustments (see the discussion on bugzilla) and still contains a FIXME note, which will be fixed by Jerry's upcoming patch for PR 78670, I hope.
Cheers, Janus
Index: gcc/fortran/trans-io.c =================================================================== --- gcc/fortran/trans-io.c (revision 246508) +++ gcc/fortran/trans-io.c (working copy) @@ -1701,23 +1701,54 @@ transfer_namelist_element (stmtblock_t * block, co /* Check if the derived type has a specific DTIO for the mode. Note that although namelist io is forbidden to have a format list, the specific subroutine is of the formatted kind. */ - if (ts->type == BT_DERIVED) + if (ts->type == BT_DERIVED || ts->type == BT_CLASS) { - gfc_symbol *dtio_sub = NULL; - gfc_symbol *vtab; - dtio_sub = gfc_find_specific_dtio_proc (ts->u.derived, - last_dt == WRITE, - true); - if (dtio_sub != NULL) + gfc_symbol *derived; + if (ts->type==BT_CLASS) + derived = ts->u.derived->components->ts.u.derived; + else + derived = ts->u.derived; + + gfc_symtree *tb_io_st = gfc_find_typebound_dtio_proc (derived, + last_dt == WRITE, true); + + if (ts->type == BT_CLASS && tb_io_st) { - dtio_proc = gfc_get_symbol_decl (dtio_sub); - dtio_proc = gfc_build_addr_expr (NULL, dtio_proc); - vtab = gfc_find_derived_vtab (ts->u.derived); - vtable = vtab->backend_decl; - if (vtable == NULL_TREE) - vtable = gfc_get_symbol_decl (vtab); - vtable = gfc_build_addr_expr (pvoid_type_node, vtable); + // polymorphic DTIO call (based on the dynamic type) + gfc_se se; + gfc_symtree *st = gfc_find_symtree (sym->ns->sym_root, sym->name); + // build vtable expr + gfc_expr *expr = gfc_get_variable_expr (st); + gfc_add_vptr_component (expr); + gfc_init_se (&se, NULL); + se.want_pointer = 1; + gfc_conv_expr (&se, expr); + vtable = se.expr; + // build dtio expr + gfc_add_component_ref (expr, + tb_io_st->n.tb->u.generic->specific_st->name); + gfc_init_se (&se, NULL); + se.want_pointer = 1; + gfc_conv_expr (&se, expr); + gfc_free_expr (expr); + dtio_proc = se.expr; } + else + { + // non-polymorphic DTIO call (based on the declared type) + gfc_symbol *dtio_sub = gfc_find_specific_dtio_proc (derived, + last_dt == WRITE, true); + if (dtio_sub != NULL) + { + dtio_proc = gfc_get_symbol_decl (dtio_sub); + dtio_proc = gfc_build_addr_expr (NULL, dtio_proc); + gfc_symbol *vtab = gfc_find_derived_vtab (derived); + vtable = vtab->backend_decl; + if (vtable == NULL_TREE) + vtable = gfc_get_symbol_decl (vtab); + vtable = gfc_build_addr_expr (pvoid_type_node, vtable); + } + } } if (ts->type == BT_CHARACTER) Index: gcc/testsuite/gfortran.dg/dtio_25.f90 =================================================================== --- gcc/testsuite/gfortran.dg/dtio_25.f90 (revision 246508) +++ gcc/testsuite/gfortran.dg/dtio_25.f90 (working copy) @@ -8,6 +8,8 @@ module m contains procedure :: write_formatted generic :: write(formatted) => write_formatted + procedure :: read_formatted + generic :: read(formatted) => read_formatted end type contains subroutine write_formatted(dtv, unit, iotype, v_list, iostat, iomsg) @@ -18,11 +20,26 @@ contains integer, intent(out) :: iostat character(*), intent(inout) :: iomsg if (iotype.eq."NAMELIST") then - write (unit, '(a,a,a,a,i5)') 'x%c="',dtv%c,'",','x%k=', dtv%k + write (unit, '(a3,a1,i3)') dtv%c,',', dtv%k else write (unit,*) dtv%c, dtv%k end if end subroutine + subroutine read_formatted(dtv, unit, iotype, v_list, iostat, iomsg) + class(t), intent(inout) :: dtv + integer, intent(in) :: unit + character(*), intent(in) :: iotype + integer, intent(in) :: v_list(:) + integer, intent(out) :: iostat + character(*), intent(inout) :: iomsg + character :: comma + if (iotype.eq."NAMELIST") then + read (unit, '(a4,a1,i3)') dtv%c, comma, dtv%k ! FIXME: need a4 here, with a3 above + else + read (unit,*) dtv%c, comma, dtv%k + end if + if (comma /= ',') call abort() + end subroutine end module program p @@ -33,9 +50,8 @@ program p namelist /nml/ x x = t('a', 5) write (buffer, nml) - if (buffer.ne.'&NML x%c="a",x%k= 5 /') call abort + if (buffer.ne.'&NML X= a, 5 /') call abort x = t('x', 0) read (buffer, nml) if (x%c.ne.'a'.or. x%k.ne.5) call abort end - Index: gcc/testsuite/gfortran.dg/dtio_27.f90 =================================================================== --- gcc/testsuite/gfortran.dg/dtio_27.f90 (nonexistent) +++ gcc/testsuite/gfortran.dg/dtio_27.f90 (working copy) @@ -0,0 +1,65 @@ +! { dg-do run } +! +! PR 78661: [OOP] Namelist output missing object designator under DTIO +! +! Contributed by Ian Harvey <ian_har...@bigpond.com> + +MODULE m + IMPLICIT NONE + TYPE :: t + CHARACTER :: c + CONTAINS + PROCEDURE :: write_formatted + GENERIC :: WRITE(FORMATTED) => write_formatted + PROCEDURE :: read_formatted + GENERIC :: READ(FORMATTED) => read_formatted + END TYPE +CONTAINS + SUBROUTINE write_formatted(dtv, unit, iotype, v_list, iostat, iomsg) + CLASS(t), INTENT(IN) :: dtv + INTEGER, INTENT(IN) :: unit + CHARACTER(*), INTENT(IN) :: iotype + INTEGER, INTENT(IN) :: v_list(:) + INTEGER, INTENT(OUT) :: iostat + CHARACTER(*), INTENT(INOUT) :: iomsg + WRITE (unit, "(A)", IOSTAT=iostat, IOMSG=iomsg) dtv%c + END SUBROUTINE + SUBROUTINE read_formatted(dtv, unit, iotype, v_list, iostat, iomsg) + CLASS(t), INTENT(INOUT) :: dtv + INTEGER, INTENT(IN) :: unit + CHARACTER(*), INTENT(IN) :: iotype + INTEGER, INTENT(IN) :: v_list(:) + INTEGER, INTENT(OUT) :: iostat + CHARACTER(*), INTENT(INOUT) :: iomsg + READ (unit, "(A)", IOSTAT=iostat, IOMSG=iomsg) dtv%c + END SUBROUTINE +END MODULE + + +PROGRAM p + + USE m + IMPLICIT NONE + character(len=4), dimension(3) :: buffer + call test_type + call test_class + +contains + + subroutine test_type + type(t) :: x + namelist /n1/ x + x = t('a') + write (buffer, n1) + if (buffer(2) /= " X=a") call abort() + end subroutine + + subroutine test_class + class(t), allocatable :: y + namelist /n2/ y + y = t('b') + write (buffer, n2) + if (buffer(2) /= " Y=b") call abort() + end subroutine + +END Index: libgfortran/io/write.c =================================================================== --- libgfortran/io/write.c (revision 246508) +++ libgfortran/io/write.c (working copy) @@ -2075,7 +2075,7 @@ nml_write_obj (st_parameter_dt *dtp, namelist_info /* Write namelist variable names in upper case. If a derived type, nothing is output. If a component, base and base_name are set. */ - if (obj->type != BT_DERIVED) + if (obj->type != BT_DERIVED || obj->dtio_sub != NULL) { namelist_write_newline (dtp); write_character (dtp, " ", 1, 1, NODELIM); @@ -2227,15 +2227,10 @@ nml_write_obj (st_parameter_dt *dtp, namelist_info int noiostat; int *child_iostat = NULL; gfc_array_i4 vlist; - gfc_class list_obj; formatted_dtio dtio_ptr = (formatted_dtio)obj->dtio_sub; GFC_DIMENSION_SET(vlist.dim[0],1, 0, 0); - list_obj.data = p; - list_obj.vptr = obj->vtable; - list_obj.len = 0; - /* Set iostat, intent(out). */ noiostat = 0; child_iostat = (dtp->common.flags & IOPARM_HAS_IOSTAT) ? @@ -2252,7 +2247,6 @@ nml_write_obj (st_parameter_dt *dtp, namelist_info child_iomsg = tmp_iomsg; child_iomsg_len = IOMSG_LEN; } - namelist_write_newline (dtp); /* If writing to an internal unit, stash it to allow the child procedure to access it. */ @@ -2261,9 +2255,23 @@ nml_write_obj (st_parameter_dt *dtp, namelist_info /* Call the user defined formatted WRITE procedure. */ dtp->u.p.current_unit->child_dtio++; - dtio_ptr ((void *)&list_obj, &unit, iotype, &vlist, - child_iostat, child_iomsg, - iotype_len, child_iomsg_len); + if (obj->type == BT_DERIVED) + { + // build a class container + gfc_class list_obj; + list_obj.data = p; + list_obj.vptr = obj->vtable; + list_obj.len = 0; + dtio_ptr ((void *)&list_obj, &unit, iotype, &vlist, + child_iostat, child_iomsg, + iotype_len, child_iomsg_len); + } + else + { + dtio_ptr (p, &unit, iotype, &vlist, + child_iostat, child_iomsg, + iotype_len, child_iomsg_len); + } dtp->u.p.current_unit->child_dtio--; goto obj_loop;