public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Tobias Burnus <tburnus@baylibre.com>
To: Jerry D <jvdelisle2@gmail.com>, gfortran <fortran@gcc.gnu.org>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [patch, libgfortran] PR114304 - [13/14 Regression] libgfortran I/O – bogus "Semicolon not allowed as separator with DECIMAL='point'"
Date: Thu, 4 Apr 2024 11:31:26 +0200	[thread overview]
Message-ID: <b4e78a90-40bc-421f-811e-fe446ab0772c@baylibre.com> (raw)
In-Reply-To: <9a848b89-ee95-44f7-8491-cbe22804edf4@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3431 bytes --]

Hi Jerry,

Jerry D wrote:
> The attached log entry and patch (git show) fixes this issue by adding 
> logic to handle spaces in eat_separators. One or more spaces by 
> themselves are a valid separator. So in this case we look at the 
> character following the spaces to see if it is a comma or semicolon.
> 
> If so, I change it to the valid separator for the given decimal mode, 
> point or comma. This allows the comma or semicolon to be interpreted as 
> a null read on the next effective item in the formatted read.
> 
> I chose a permissive approach here that allows reads to proceed when the
> input line is mal-formed with an incorrect separator as long as there is 
> at least one space in front of it.

First: Consider also adding 'PR fortran/105473' to the commit log
as the PRs are closely related, albeit this PR is different-

The patch looks mostly like I would expect, except for decimal='point' 
and a ';' which is *not* preceded by a space.

Thanks for working on it.

Regarding the 'except' case:

* * *

If I try your patch with the testcase of at comment 19,

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114304#c19https://gcc.gnu.org/bugzilla/attachment.cgi?id=57695 ,

I do note that with 'decimal=point', a tailing semicolon is silently
accepted – even if not proceeded by a space.

I think such code is invalid – and you could consider to reject it.
Otherwise, the handling all seems to be in line with the Fortran spec.

i.e. for the following string, I had *expected an error*:

  point, isreal =  F , testinput = ";"n=          42  ios=           0
  point, isreal =  F , testinput = "5;"n=           5  ios=           0
  point, isreal =  T , testinput = "8;"r=   8.00000000      ios= 0
  point, isreal =  T , testinput = "3.3;"r=   3.29999995      ios= 0
  point, isreal =  T , testinput = "3,3;"r=   3.00000000      ios= 0

while I think the following is OK (i.e. no error is what I expect) due 
to the the space before the ';'.

  point, isreal =  F , testinput = "7 ;"n=           7  ios= 0
  point, isreal =  T , testinput = "9 ;"r=   9.00000000      ios= 0
  point, isreal =  T , testinput = "4.4 ;"r=   4.40000010      ios=0
  point, isreal =  T , testinput = "9 ;"r=   9.00000000      ios= 0
  point, isreal =  T , testinput = "4,4 ;"r=   4.00000000      ios= 0

* * *

Looking at the other compilers, ifort, ifx and Flang do issue an error 
here. Likewise, g95 seems to yield an error in this case (see below).

I do note that the Lapack testcase that triggered this PR did have such 
a code - but it was then changed because g95 did not like it:

https://github.com/Reference-LAPACK/lapack/commit/64e8a7500d817869e5fcde35afd39af8bc7a8086

In terms of gfortran: until recently did accept it (all versions, 
including 13+14); it then rejected it due to the change in PR105473 (GCC 
14/mainline, backported to 13)– but I now think it rightly did so. With 
the current patch, it is accepted again.

* * *

I have attached the modified testcase linked above; consider adding it 
as well. - Changes to the one of the attachment:
- I added a few additional (albeit boring) tests
- I added an expected output + error diagnostic.

The testcase assumes an error for ';' as separator (with 'point'), 
unless there is a space before it.

[If we want to not diagnose this as vendor extension, we really need to 
add a comment to that testcase besides changing valid = .false. to .true.]

Tobias

[-- Attachment #2: pr114304.f90 --]
[-- Type: text/x-fortran, Size: 4316 bytes --]

! { dg-do run }
!
! PR fortran/114304
!
! See also PR fortran/105473
!
! Testing: Does list-directed reading an integer/real allows some non-integer input?
!
! Note: GCC result comments before fix of this PR.

  implicit none
  call t(.true.,  'comma', ';') ! No error shown
  call t(.false., 'point', ';') ! /!\ gfortran: no error, others: error
  call t(.false., 'comma', ',') ! Error shown
  call t(.true.,  'point', ',') ! No error shown
  call t(.false., 'comma', '.') ! Error shown
  call t(.false., 'point', '.') ! Error shown
  call t(.false., 'comma', '5.') ! Error shown
  call t(.false., 'point', '5.') ! gfortran/flang: Error shown, ifort: no error
  call t(.false., 'comma', '5,') ! gfortran: error; others: no error
  call t(.true.,  'point', '5,') ! No error shown
  call t(.true.,  'comma', '5;') ! No error shown
  call t(.false., 'point', '5;') ! /!\ gfortran: no error shown, others: error
  call t(.true.,  'comma', '7 .') ! No error shown
  call t(.true.,  'point', '7 .') ! No error shown
  call t(.true.,  'comma', '7 ,') ! /!\ gfortran: error; others: no error
  call t(.true.,  'point', '7 ,') ! No error shown
  call t(.true.,  'comma', '7 ;') ! No error shown
  call t(.true.,  'point', '7 ;') ! No error shown

!  print *, '---------------'

  call t(.false., 'comma', '8.', .true.) ! Error shown
  call t(.true.,  'point', '8.', .true.) ! gfortran/flang: Error shown, ifort: no error
  call t(.true.,  'comma', '8,', .true.) ! gfortran: error; others: no error
  call t(.true.,  'point', '8,', .true.) ! No error shown
  call t(.true.,  'comma', '8;', .true.) ! No error shown
  call t(.false., 'point', '8;', .true.) ! /!\ gfortran: no error shown, others: error
  call t(.true.,  'comma', '9 .', .true.) ! No error shown
  call t(.true.,  'point', '9 .', .true.) ! No error shown
  call t(.true.,  'comma', '9 ,', .true.) ! /!\ gfortran: error; others: no error
  call t(.true.,  'point', '9 ,', .true.) ! No error shown
  call t(.true.,  'comma', '9 ;', .true.) ! No error shown
  call t(.true.,  'point', '9 ;', .true.) ! No error shown
  call t(.false., 'comma', '3,3.', .true.) ! Error shown
  call t(.false., 'point', '3.3.', .true.) ! Error shown
  call t(.false., 'comma', '3,3,', .true.) ! gfortran/flang: no error; ifort: error
  call t(.true.,  'comma', '3,3;', .true.) ! No error shown
  call t(.false., 'point', '3.3;', .true.) ! gfortran/flang: no error; ifort: error
  call t(.true.,  'comma', '4,4 .', .true.) ! N error shown
  call t(.true.,  'point', '4.4 .', .true.) ! No error shown
  call t(.true.,  'comma', '4,4 ,', .true.) ! /!\ gfortran: error; others: no error
  call t(.true.,  'point', '4.4 ,', .true.) ! No error shown
  call t(.true.,  'comma', '4,4 ;', .true.) ! No error shown
  call t(.true.,  'point', '4.4 ;', .true.) ! No error shown

!  print *, '---------------'

  call t(.true.,  'comma', '8', .true.)
  call t(.true.,  'point', '8', .true.)
  call t(.true.,  'point', '9 ;', .true.)
  call t(.true.,  'comma', '3;3.', .true.)
  call t(.true.,  'point', '3,3.', .true.)
  call t(.true.,  'comma', '3;3,', .true.)
  call t(.true.,  'comma', '3;3;', .true.)
  call t(.true.,  'point', '3,3;', .true.)
  call t(.true.,  'comma', '4;4 .', .true.)
  call t(.true.,  'point', '4,4 .', .true.)
  call t(.true.,  'comma', '4;4 ,', .true.)
  call t(.true.,  'point', '4,4 ,', .true.)
  call t(.true.,  'comma', '4;4 ;', .true.)
  call t(.true.,  'point', '4,4 ;', .true.)
contains
subroutine t(valid, dec, testinput, isreal)
  logical, value :: valid
  character(len=*) :: dec, testinput
  logical, optional :: isreal
  logical :: isreal2
  integer n,ios
  real :: r
  r = 42; n = 42
  isreal2 = .false.
  if (present(isreal)) isreal2 = isreal

  if (isreal2) then
    read(testinput,*,decimal=dec,iostat=ios) r
    if ((valid .and. ios /= 0) .or. (.not.valid .and. ios == 0)) then
      print '(*(g0))', valid, ', ', dec,', isreal = ',isreal2,', testinput = "',testinput,'"',', r=',r,' ios=',ios
      print *, 'ERROR'
      stop 1
    end if
  else
    read(testinput,*,decimal=dec,iostat=ios) n
    if ((valid .and. ios /= 0) .or. (.not.valid .and. ios == 0)) then
      print '(*(g0))', valid, ', ', dec,', isreal = ',isreal2,', testinput = "',testinput,'"',', n=',n,' ios=',ios
      print *, 'ERROR'
      stop 1
    end if
  end if
end
end program

  parent reply	other threads:[~2024-04-04  9:31 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-04  1:33 Jerry D
2024-04-04  8:17 ` Paul Richard Thomas
2024-04-04  9:31 ` Tobias Burnus [this message]
2024-04-04 20:05   ` Jerry D
2024-04-04 21:04   ` Jerry D
2024-04-04 21:41     ` Tobias Burnus
2024-04-05 17:47       ` Jerry D
2024-04-06  2:38         ` Jerry D
2024-04-06  5:17           ` Tobias Burnus
2024-04-08  9:53           ` [Patch] Fortran: List-directed read - accept again tab as alternative to space as separator [PR114304] (was: [patch, libgfortran] PR114304 - [13/14 Regression] libgfortran I/O – bogus "Semicolon not allowed as separator with DECIMAL='point'") Tobias Burnus
2024-04-08 18:21             ` [Patch] Fortran: List-directed read - accept again tab as alternative to space as separator [PR114304] Jerry D

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b4e78a90-40bc-421f-811e-fe446ab0772c@baylibre.com \
    --to=tburnus@baylibre.com \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jvdelisle2@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).