public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jerry D <jvdelisle2@gmail.com>
To: Tobias Burnus <tburnus@baylibre.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: Fri, 5 Apr 2024 19:38:09 -0700	[thread overview]
Message-ID: <cbb83676-81c5-4a1d-addd-9c7b0f4b1e64@gmail.com> (raw)
In-Reply-To: <6a742cef-5321-4b34-a2f0-870abd1ba82a@gmail.com>

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

On 4/5/24 10:47 AM, Jerry D wrote:
> On 4/4/24 2:41 PM, Tobias Burnus wrote:
>> Hi Jerry,
>>
>> I think for the current testcases, I like the patch – the question is 
>> only what's about:
>>
>>    ',3' as input for 'comma'   (or '.3' as input for 'point')
>>
>> For 'point' – 0.3 is read and ios = 0 (as expected)
>> But for 'comma':
>> * GCC 12 reads nothing and has ios = 0.
>> * GCC 13/mainline has an error (ios != 0 – and reads nothing)
>> * GCC with your patch: Same result: ios != 0 and nothing read.
>>
>> Expected: Same as with ','/'comma' – namely: read-in value is 0.3.
>> → https://godbolt.org/z/4rc8fz4sT for the full example, which works 
>> with ifort, ifx and flang
>>
>> * * *
>>
>> Can you check and fix this? It looks perfectly valid to me to have 
>> remove the '0' in the floating point numbers '0.3' or '0,3' seems to 
>> be permitted – and it works for '.' (with 'point') but not for ',' 
>> (with 'comma').
>>
> Yes, I found the spot to fix this.
> 
>> F2023's "13.10.3.1 List-directed input forms" refers to "13.7.2.3.2 F 
>> editing", which states:
>>
>> "The standard form of the input field [...] The form of the mantissa 
>> is an optional sign, followed by a string of one or more digits 
>> optionally containing a decimal symbol."
>>
>> The latter does not require that the digit has to be before the 
>> decimal sign and as for output, it is optional, it is surely intended 
>> that ",3" is a valid floating-point number for decimal='comma'.
>>
> 
> Agree
> 
>> * * *
>>
>> I extended the testcase to check for this – see attached diff. All 
>> 'point' work, all 'comma' fail.
>>
>> Thanks for working on this!
>>
>> Tobias
> 
> Thanks much. After I fix it, I will use your extended test case in the 
> test suite.
> 
> Jerry -


See attached updated patch.

Regressions tested on x86-64. OK for trunk and 13 after a bit.

Jerry -

[-- Attachment #2: submit-3.diff --]
[-- Type: text/x-patch, Size: 8065 bytes --]

commit 690b9fa57d95796ba0e92a172e1490601f25e03a
Author: Jerry DeLisle <jvdelisle@gcc.gnu.org>
Date:   Fri Apr 5 19:25:13 2024 -0700

    libfortran: Fix handling of formatted separators.
    
            PR libfortran/114304
            PR libfortran/105473
    
    libgfortran/ChangeLog:
    
            * io/list_read.c (eat_separator): Add logic to handle spaces
            preceding a comma or semicolon such that that a 'null' read
            occurs without error at the end of comma or semicolon
            terminated input lines. Add check and error message for ';'.
            (list_formatted_read_scalar): Treat comma as a decimal point
            when specified by the decimal mode on the first item.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/pr105473.f90: Modify to verify new error message.
            * gfortran.dg/pr114304.f90: New test.

diff --git a/gcc/testsuite/gfortran.dg/pr105473.f90 b/gcc/testsuite/gfortran.dg/pr105473.f90
index 2679f6bb447..863a312c794 100644
--- a/gcc/testsuite/gfortran.dg/pr105473.f90
+++ b/gcc/testsuite/gfortran.dg/pr105473.f90
@@ -9,11 +9,11 @@
   n = 999; m = 777; r=1.2345
   z = cmplx(0.0,0.0)
 
-! Check that semi-colon is allowed as separator with decimal=point.
+! Check that semi-colon is not allowed as separator with decimal=point.
   ios=0
   testinput = '1;17;3.14159'
   read(testinput,*,decimal='point',iostat=ios) n, m, r
-  if (ios /= 0) stop 1
+  if (ios /= 5010) stop 1
 
 ! Check that semi-colon allowed as a separator with decimal=point.
   ios=0
diff --git a/gcc/testsuite/gfortran.dg/pr114304.f90 b/gcc/testsuite/gfortran.dg/pr114304.f90
new file mode 100644
index 00000000000..2f913f1ab34
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr114304.f90
@@ -0,0 +1,114 @@
+! { dg-do run }
+!
+! PR fortran/114304
+!
+! See also PR fortran/105473
+!
+! Testing: Does list-directed reading an integer/real allow 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.)
+
+  call t2('comma', ',2')
+  call t2('point', '.2')
+  call t2('comma', ',2;')
+  call t2('point', '.2,')
+  call t2('comma', ',2 ,')
+  call t2('point', '.2 .')
+contains
+subroutine t2(dec, testinput)
+  character(*) :: dec, testinput
+  integer ios
+  real :: r
+  r = 42
+  read(testinput,*,decimal=dec, iostat=ios) r
+  if (ios /= 0 .or.  abs(r - 0.2) > epsilon(r)) then
+    stop 3 
+  end if
+end
+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
+      stop 1
+    end if
+  else
+    read(testinput,*,decimal=dec,iostat=ios) n
+    if ((valid .and. ios /= 0) .or. (.not.valid .and. ios == 0)) then
+      stop 1
+    end if
+  end if
+end
+end program
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index fb3f7dbc34d..b56f2a4e6d6 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -461,11 +461,30 @@ eat_separator (st_parameter_dt *dtp)
   int c, n;
   int err = 0;
 
-  eat_spaces (dtp);
   dtp->u.p.comma_flag = 0;
+  c = next_char (dtp);
+  if (c == ' ')
+    {
+      eat_spaces (dtp);
+      c = next_char (dtp);
+      if (c == ',')
+	{
+	  if (dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+	    unget_char (dtp, ';');
+	  dtp->u.p.comma_flag = 1;
+	  eat_spaces (dtp);
+	  return err;
+	}
+      if (c == ';')
+	{
+	  if (dtp->u.p.current_unit->decimal_status == DECIMAL_POINT)
+	    unget_char (dtp, ',');
+	  dtp->u.p.comma_flag = 1;
+	  eat_spaces (dtp);
+	  return err;
+	}
+    }
 
-  if ((c = next_char (dtp)) == EOF)
-    return LIBERROR_END;
   switch (c)
     {
     case ',':
@@ -476,8 +495,18 @@ eat_separator (st_parameter_dt *dtp)
 	  unget_char (dtp, c);
 	  break;
 	}
-    /* Fall through. */
+      dtp->u.p.comma_flag = 1;
+      eat_spaces (dtp);
+      break;
+
     case ';':
+      if (dtp->u.p.current_unit->decimal_status == DECIMAL_POINT)
+	{
+	  generate_error (&dtp->common, LIBERROR_READ_VALUE,
+	   "Semicolon not allowed as separator with DECIMAL='point'");
+	  unget_char (dtp, c);
+	  break;
+	}
       dtp->u.p.comma_flag = 1;
       eat_spaces (dtp);
       break;
@@ -2144,7 +2173,9 @@ list_formatted_read_scalar (st_parameter_dt *dtp, bt type, void *p,
 	  err = LIBERROR_END;
 	  goto cleanup;
 	}
-      if (is_separator (c))
+      if (c == ',' && dtp->u.p.current_unit->decimal_status == DECIMAL_COMMA)
+	c = '.';
+      else if (is_separator (c))
 	{
 	  /* Found a null value.  */
 	  dtp->u.p.repeat_count = 0;

  reply	other threads:[~2024-04-06  2:38 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
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 [this message]
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=cbb83676-81c5-4a1d-addd-9c7b0f4b1e64@gmail.com \
    --to=jvdelisle2@gmail.com \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=tburnus@baylibre.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).