[PATCH] Fix mishandling to tab formatting
Jerry D <[email protected]> Mon, 15 Jun 2026 12:54:22 -0700
| Newsgroups | gmane.comp.gcc.patches,gmane.comp.gcc.fortran |
|---|---|
| Message-ID | <[email protected]> |
The attached patch I had to redo because I was asked to no longer use LLM for assistance until the gcc LLM Working Group comes up with a policy. I dont know when that might happen so I am not using LLM at the moment. This patch reworked by myself and retested on X86_64. I have no plans to backport this. Ok for mainline? Best regards, Jerry --- commit fb37c5b7548faf3094ccae9aa8f187cb3277fc20 Author: Jerry DeLisle <[email protected]> Date: Mon Jun 15 11:58:31 2026 -0700 libfortran: [PR114618] Format produces incorrect output when contains 1x When tabbing left or right it is possible to land in the format buffer where some text is over written or skipped improperly. The bad formatting depended on whether stream I/O is used or regular I/O. The max position has to be calculated correctly in these situations. One existing test case is renamed to align with other format T/TL/TR test cases. PR libfortran/114618 libgfortran/ChangeLog: * io/transfer.c (formatted_transfer_scalar_write): Determine possible new max_pos based on file I/O method and adjust accordingly gcc/testsuite/ChangeLog: * gfortran.dg/pr114618.f90: Move to... * gfortran.dg/fmt_t_10.f90: ...here. * gfortran.dg/fmt_t_11.f90: New test. ---
pr114618.diff
(text/x-patch, 5.5 KB)
commit fb37c5b7548faf3094ccae9aa8f187cb3277fc20 Author: Jerry DeLisle <[email protected]> Date: Mon Jun 15 11:58:31 2026 -0700 libfortran: [PR114618] Format produces incorrect output when contains 1x When tabbing left or right it is possible to land in the format buffer where some text is over written or skipped improperly. The bad formatting depended on whether stream I/O is used or regular I/O. The max position has to be calculated correctly in these situations. One existing test case is renamed to align with other format T/TL/TR test cases. PR libfortran/114618 libgfortran/ChangeLog: * io/transfer.c (formatted_transfer_scalar_write): Determine possible new max_pos based on file I/O method and adjust accordingly gcc/testsuite/ChangeLog: * gfortran.dg/pr114618.f90: Move to... * gfortran.dg/fmt_t_10.f90: ...here. * gfortran.dg/fmt_t_11.f90: New test. diff --git a/gcc/testsuite/gfortran.dg/pr114618.f90 b/gcc/testsuite/gfortran.dg/fmt_t_10.f90 similarity index 94% rename from gcc/testsuite/gfortran.dg/pr114618.f90 rename to gcc/testsuite/gfortran.dg/fmt_t_10.f90 index 835597b8513..1f714d24d4e 100644 --- a/gcc/testsuite/gfortran.dg/pr114618.f90 +++ b/gcc/testsuite/gfortran.dg/fmt_t_10.f90 @@ -1,7 +1,7 @@ ! { dg-do run } ! PR114618 Format produces incorrect output when contains 1x, ok when uses " " ! aside: Before patch output1 is garbage. -program pr114618 +program fmt_t_10 implicit none integer, parameter :: wp = kind(0d0) real(kind=wp) :: pi = 3.14159265358979323846264338_wp @@ -12,4 +12,4 @@ program pr114618 write (output2, fmt2) 'RADIX', radix(pi) if (output1 /= 'RADIX.............. 2') stop 1 if (output2 /= 'RADIX ............. 2') stop 2 -end program pr114618 +end program fmt_t_10 diff --git a/gcc/testsuite/gfortran.dg/fmt_t_11.f90 b/gcc/testsuite/gfortran.dg/fmt_t_11.f90 new file mode 100644 index 00000000000..7c4300e616b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/fmt_t_11.f90 @@ -0,0 +1,61 @@ +! { dg-do run } +! PR libfortran/114618 - Test TL, TR, and T specifiers in combination for +! sequential and stream formatted file I/O. +program fmt_t_11 + implicit none + integer :: u + character(len=20) :: line + + ! --- Sequential formatted file tests --- + + ! T backward then TR forward into already-written content + open (newunit=u, status='scratch', form='formatted') + write (u, '(10("X"),t3,"AB",tr3,"C")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:10) /= 'XXABXXXCXX') stop 1 + + ! TL backward then TR forward into already-written content + open (newunit=u, status='scratch', form='formatted') + write (u, '("HELLO123",tl5,"AB",tr3,"Z")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:9) /= 'HELAB123Z') stop 2 + + ! T, TL, and TR all combined in one format + open (newunit=u, status='scratch', form='formatted') + write (u, '(t7,"*",tl5,"AB",tr3,"Z")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:8) /= ' AB *Z') stop 3 + + ! --- Stream formatted file tests --- + + ! T backward then TR forward into already-written content + open (newunit=u, status='scratch', form='formatted', access='stream') + write (u, '(10("X"),t3,"AB",tr3,"C")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:10) /= 'XXABXXXCXX') stop 4 + + ! TL backward then TR forward into already-written content + open (newunit=u, status='scratch', form='formatted', access='stream') + write (u, '("HELLO123",tl5,"AB",tr3,"Z")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:9) /= 'HELAB123Z') stop 5 + + ! T, TL, and TR all combined in one format + open (newunit=u, status='scratch', form='formatted', access='stream') + write (u, '(t7,"*",tl5,"AB",tr3,"Z")') + rewind (u) + read (u, '(a)') line + close (u) + if (line(1:8) /= ' AB *Z') stop 6 + +end program fmt_t_11 diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c index d88cd810529..de7b6d7df35 100644 --- a/libgfortran/io/transfer.c +++ b/libgfortran/io/transfer.c @@ -2162,7 +2162,7 @@ formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kin } if (is_stream_io(dtp)) - bytes_used = dtp->u.p.current_unit->fbuf->act; + bytes_used = dtp->u.p.current_unit->fbuf->pos; else bytes_used = dtp->u.p.current_unit->recl - dtp->u.p.current_unit->bytes_left; @@ -2420,6 +2420,27 @@ formatted_transfer_scalar_write (st_parameter_dt *dtp, bt type, void *p, int kin dtp->u.p.skips += f->u.n; tab_pos = bytes_used + dtp->u.p.skips - 1; dtp->u.p.pending_spaces = tab_pos - dtp->u.p.max_pos + 1; + if (dtp->u.p.pending_spaces < 0 && dtp->u.p.skips > 0) + { + /* The advance falls within already-written content (e.g. after + a backward tab). Advance the position without overwriting + the existing characters. */ + gfc_offset new_max; + write_x (dtp, dtp->u.p.skips, 0); + + /* Adjust the max position depending on the type of write. */ + if (is_stream_io (dtp)) + new_max = dtp->u.p.current_unit->fbuf->act; + else + new_max = dtp->u.p.current_unit->recl + - dtp->u.p.current_unit->bytes_left; + + dtp->u.p.max_pos = dtp->u.p.max_pos > new_max + ? dtp->u.p.max_pos : new_max; + + dtp->u.p.skips = dtp->u.p.pending_spaces = 0; + break; + } dtp->u.p.pending_spaces = dtp->u.p.pending_spaces < 0 ? f->u.n : dtp->u.p.pending_spaces;