[Committed] PR fortran/54072 -- More fun with BOZ

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[Committed] PR fortran/54072 -- More fun with BOZ

Steve Kargl
I've committed the attached patch as a follow-up to
the recent BOZ (r273747).  It removes a few leftover
comments as well as fixes the PR.

2019-07-23  Steven G. Kargl  <[hidden email]>

 PR fortran/54072
 * check.c (gfc_invalid_boz): Fix comment.
 (illegal_boz_arg): New function.
 (gfc_check_transfer): Use to arguments.
 (gfc_check_storage_size): Ditto.
 (gfc_check_complex): Remove leftover comment from BOZ patch.
 * primary.c (match_boz_constant): Remove leftover comment.


2019-07-23  Steven G. Kargl  <[hidden email]>

 PR fortran/54072
 * gfortran.dg/illegal_boz_arg_1.f90: New tests.

--
Steve

pr54072.diff (3K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Committed] PR fortran/54072 -- More fun with BOZ

Mark Eggleston
Steve,

BOZ problems in the following areas

  * use of logical and character variables with BOZ constants
  * comparisons with BOZ constants
  * DATA statements

Comparing 9.1 and trunk:

character variables (9.1)

  * old style initialisation - not allowed (Incompatible types)
  * new style initialisation - not allowed (Cannot convert)
  * assignment - not allowed (Cannot convert)
  * DATA statement not allowed

character variables (trunk with -fallow-invalid-boz)

  * old style initialisation - not allowed (type mismatch)
  * new style initialisation - not allowed (Unclassifiable statement)
  * assignment - not allowed (Invalid use)
  * DATA statement allowed

logical variables (9.1)

  * old style initialisation - not allowed (Incompatible types)
  * new style initialisation - allowed with warning
  * assignment - allowed with warning
  * DATA statement not allowed (Incompatible types)

logical variables (trunk with -fallow-invalid-boz)

  * old style initialisation - not allowed (type mismatch)
  * new style initialisation - not allowed (Unclassifiable statement)
  * assignment - not allowed (invalid use)
  * DATA statement allowed

Comparisons with BOZ constants was allowed using 9.1 with
-Wconversion-extra:

     5 |         if (i4 .eq. z'1000') then
       |            1
Warning: Conversion from INTEGER(4) to INTEGER(16) at (1)
[-Wconversion-extra]

Using trunk  with -fallow-invalid-boz comparison is not allowed:

     5 |         if (i4 .eq. z'1000') then
       |            1
Error: Operands of comparison operator '.eq.' at (1) are INTEGER(4)/BOZ

I would have expected a suitable warning about using the BOZ in an
inappropriate place.

DATA statements for logical and character variable compile but do not work:

program test
   character(4) :: c
   data c / z'41424344' /
   write(*, *) "'" // c // "'", transfer(c, 0_4)
end program test

Outputs:

  ''           0

program test
   logical(4) b / z'00000001' /
   write(*, *) b
end program test

Outputs:

  F

Apologies if this should have been reported via bugzilla. If so let me
know and I'll submit it split into 2 or 3 bug reports.

The trunk compiler was built on x86_64 hardware using code from
Subversion revision 274157.


regards,
Mark Eggleston


On 24/07/2019 00:05, Steve Kargl wrote:

> I've committed the attached patch as a follow-up to
> the recent BOZ (r273747).  It removes a few leftover
> comments as well as fixes the PR.
>
> 2019-07-23  Steven G. Kargl  <[hidden email]>
>
>   PR fortran/54072
>   * check.c (gfc_invalid_boz): Fix comment.
>   (illegal_boz_arg): New function.
>   (gfc_check_transfer): Use to arguments.
>   (gfc_check_storage_size): Ditto.
>   (gfc_check_complex): Remove leftover comment from BOZ patch.
>   * primary.c (match_boz_constant): Remove leftover comment.
>
>
> 2019-07-23  Steven G. Kargl  <[hidden email]>
>
>   PR fortran/54072
>   * gfortran.dg/illegal_boz_arg_1.f90: New tests.
>
--
https://www.codethink.co.uk/privacy.html

Reply | Threaded
Open this post in threaded view
|

Re: [Committed] PR fortran/54072 -- More fun with BOZ

Steve Kargl
On Wed, Aug 07, 2019 at 01:58:17PM +0100, Mark Eggleston wrote:
>
> BOZ problems in the following areas
>
>   * use of logical and character variables with BOZ constants
>   * comparisons with BOZ constants
>   * DATA statements
>
> Comparing 9.1 and trunk:

The comparison is somewhat irrelevant.  I removed a
a number of undocumented extensions when I made the
handling of BOZ conform to the F2018 Fortran standard.

> Comparisons with BOZ constants was allowed using 9.1 with
> -Wconversion-extra:
>
>      5 |         if (i4 .eq. z'1000') then
>        |            1
> Warning: Conversion from INTEGER(4) to INTEGER(16) at (1)
> [-Wconversion-extra]

This is the old behavior were a BOZ upon parsing is
immediately converted to an INTEGER with the widest decimal
range.  It is a holdover from when I made BOZ work in
accordance with the Fortran 95 standard, where a BOZ is
only allowed as a data-stmt-constant.  On your target, that
is INTEGER(16).  Because of that conversion, a BOZ could
be used anywhere an INTEGER can be used.

> Using trunk  with -fallow-invalid-boz comparison is not allowed:
>
>      5 |         if (i4 .eq. z'1000') then
>        |            1
> Error: Operands of comparison operator '.eq.' at (1) are INTEGER(4)/BOZ
>
> I would have expected a suitable warning about using the BOZ in an
> inappropriate place.

A BOZ cannot be an operand to a binary operator.

Consider

x = 1.0 + z'40490fdb'   ! Is this 4.14159.... or 1.07853005E+09

y = z'40490fdb' + z'40490fbd' + 1. ! Is this 2*pi+1 or 2.15...E+09.

Note, gfortran does left-to-right evaluation, but Fortran standard
does not require this ordering.  For 'x' it is possible to convert
op2 to the type of op1, which would give 4.1415....  That behavior
is different in comparison to the historical accident of 1.08E9.
For 'y', there is no valid conversion of op1 into op2.  In older
versions, the first addition is of 2 INTEGER(16).  The second
addition converts a INTEGER(16) to a REAL(4) and then adds.

>
> DATA statements for logical and character variable compile but do not work:
>
> program test
>    character(4) :: c
>    data c / z'41424344' /
>    write(*, *) "'" // c // "'", transfer(c, 0_4)
> end program test
>
> Outputs:
>
>   ''           0
>
> program test
>    logical(4) b / z'00000001' /
>    write(*, *) b
> end program test
>
> Outputs:
>
>   F

From the current Fortran working documenti, page 111:

   If a data-stmt-constant is a boz-literal-constant, the corresponding
   variable shall be of type integer.  The boz-literal-constant is
   treated as if it were converted by the intrinsic function INT(16.9.100)
   to type integer with the kind type parameter of the variable.

For the second program, I get

gfcx -o z a.f90 && ./z
a.f90:8:26:

    8 | logical(4) b / z'00000001' /
      |                          1
Error: BOZ at (1) cannot appear in an old-style initialization

which to me is acceptable.

For the first testcase, that should be rejected.  I thought I had
that fixed in my tree.  It probably got lost in one of numerous
versions of the BOZ rewrite.

> Apologies if this should have been reported via bugzilla. If so let me
> know and I'll submit it split into 2 or 3 bug reports.

Reporting it here is fine.  I'll look at rejecting the one code
that compiles (as it shouldn't).  And, I'll toy with adding BOZ
as an operand of binary operators (I actually had this working in
an ancient patch) under -fallow-invalid-boz.



--
Steve
Reply | Threaded
Open this post in threaded view
|

Re: [Committed] PR fortran/54072 -- More fun with BOZ

Mark Eggleston

On 07/08/2019 17:09, Steve Kargl wrote:

> On Wed, Aug 07, 2019 at 01:58:17PM +0100, Mark Eggleston wrote:
>> BOZ problems in the following areas
>>
>>    * use of logical and character variables with BOZ constants
>>    * comparisons with BOZ constants
>>    * DATA statements
>>
>> Comparing 9.1 and trunk:
> The comparison is somewhat irrelevant.  I removed a
> a number of undocumented extensions when I made the
> handling of BOZ conform to the F2018 Fortran standard.
>
>> Comparisons with BOZ constants was allowed using 9.1 with
>> -Wconversion-extra:
>>
>>       5 |         if (i4 .eq. z'1000') then
>>         |            1
>> Warning: Conversion from INTEGER(4) to INTEGER(16) at (1)
>> [-Wconversion-extra]
> This is the old behavior were a BOZ upon parsing is
> immediately converted to an INTEGER with the widest decimal
> range.  It is a holdover from when I made BOZ work in
> accordance with the Fortran 95 standard, where a BOZ is
> only allowed as a data-stmt-constant.  On your target, that
> is INTEGER(16).  Because of that conversion, a BOZ could
> be used anywhere an INTEGER can be used.

Other invalid BOZ usage is enable with -fallow-invalid-box, why not this?

This is from a test suite for a customer to check that gfortran supports
various legacy features. This feature is supported by all the compilers
they use including gfortran up to 9.1. This change will break legacy
code. Of course the best solution is to update their code i.e:

if (i4 .eq. int(z'1000',4)) then

I'll check whether the old behaviour is still required.

>
>> Using trunk  with -fallow-invalid-boz comparison is not allowed:
>>
>>       5 |         if (i4 .eq. z'1000') then
>>         |            1
>> Error: Operands of comparison operator '.eq.' at (1) are INTEGER(4)/BOZ
>>
>> I would have expected a suitable warning about using the BOZ in an
>> inappropriate place.
> A BOZ cannot be an operand to a binary operator.
>
> Consider
>
> x = 1.0 + z'40490fdb'   ! Is this 4.14159.... or 1.07853005E+09
>
> y = z'40490fdb' + z'40490fbd' + 1. ! Is this 2*pi+1 or 2.15...E+09.
>
> Note, gfortran does left-to-right evaluation, but Fortran standard
> does not require this ordering.  For 'x' it is possible to convert
> op2 to the type of op1, which would give 4.1415....  That behavior
> is different in comparison to the historical accident of 1.08E9.
> For 'y', there is no valid conversion of op1 into op2.  In older
> versions, the first addition is of 2 INTEGER(16).  The second
> addition converts a INTEGER(16) to a REAL(4) and then adds.
>
>> DATA statements for logical and character variable compile but do not work:
>>
>> program test
>>     character(4) :: c
>>     data c / z'41424344' /
>>     write(*, *) "'" // c // "'", transfer(c, 0_4)
>> end program test
>>
>> Outputs:
>>
>>    ''           0
>>
>> program test
>>     logical(4) b / z'00000001' /
>>     write(*, *) b
>> end program test
>>
>> Outputs:
>>
>>    F
>  From the current Fortran working documenti, page 111:
>
>     If a data-stmt-constant is a boz-literal-constant, the corresponding
>     variable shall be of type integer.  The boz-literal-constant is
>     treated as if it were converted by the intrinsic function INT(16.9.100)
>     to type integer with the kind type parameter of the variable.
do have a link for the current workinng documentation it'll be useful.

>
> For the second program, I get
>
> gfcx -o z a.f90 && ./z
> a.f90:8:26:
>
>      8 | logical(4) b / z'00000001' /
>        |                          1
> Error: BOZ at (1) cannot appear in an old-style initialization
>
> which to me is acceptable.

whoops, I added the wrong program, it should have had a DATA statement
in it...

program test
    logical(4) b
    data b / z'00000001' /
    write(*, *) b
end program test

> For the first testcase, that should be rejected.  I thought I had
> that fixed in my tree.  It probably got lost in one of numerous
> versions of the BOZ rewrite.
>
>> Apologies if this should have been reported via bugzilla. If so let me
>> know and I'll submit it split into 2 or 3 bug reports.
> Reporting it here is fine.  I'll look at rejecting the one code
> that compiles (as it shouldn't).  And, I'll toy with adding BOZ
> as an operand of binary operators (I actually had this working in
> an ancient patch) under -fallow-invalid-boz.
>
>
regards,

Mark

--
https://www.codethink.co.uk/privacy.html

Reply | Threaded
Open this post in threaded view
|

Re: [Committed] PR fortran/54072 -- More fun with BOZ

Steve Kargl
In reply to this post by Steve Kargl
On Thu, Aug 08, 2019 at 09:31:37AM +0100, Mark Eggleston wrote:

>
> On 07/08/2019 19:56, Steve Kargl wrote:
> > On Wed, Aug 07, 2019 at 09:09:49AM -0700, Steve Kargl wrote:
> >> On Wed, Aug 07, 2019 at 01:58:17PM +0100, Mark Eggleston wrote:
> >>> DATA statements for logical and character variable compile but do not work:
> >>>
> >>> program test
> >>>     character(4) :: c
> >>>     data c / z'41424344' /
> >>>     write(*, *) "'" // c // "'", transfer(c, 0_4)
> >>> end program test
> >>>
> >>> Outputs:
> >>>
> >>>    ''           0
> > Prior versions of gfortran give
> >
> > % gfc9 -c a.f90
> > a.f90:3:10:
> >
> >      3 |    data c / z'41424344' /
> >        |          1
> > Error: Incompatible types in DATA statement at (1); attempted conversion of INTEGER(16) to CHARACTER(1)
> >
> > I have a patch that now does
> >
> > gfcx -c a.f90
> > a.f90:3:10-23:
> >
> >      3 |    data c / z'41424344' /
> >        |          1            2
> > Error: data-stmt-object at (1) has type 'CHARACTER', which conflicts with the BOZ literal constant at (2)
>
> Is there any particular reason for reverting to the earlier behaviour
> instead of fixing the contents of c?
>
> "C4102 (R463) A boz-literal-constant shall appear only as a
> data-stmt-constant in a DATA statement, or where explicitly allowed in
> subclause 13.7 as an actual argument of an intrinsic procedure." from
> the 2008 standard implies that the use of a BOZ in the data statement of
> a character variable is allowed, it doesn't say that it is restricted to
> numeric types.

You're looking at the wrong part of the Fortran standard,
and yes, I know it can sometimes be hard to find the right
text.

Fortran working document, page. 111.

   If a data-stmt-constant is a boz-literal-constant, the corresponding
   variable shall be of type integer.

You should be able to find some version of this sentence in all version
of the Fortran standard starting with Fortran 95.  As an extension,
gfortran allows a data-stmt-object to also have a type real.


> > BTW, -fallow-invalid-boz does enable all previous broken
> > usages of BOZ.

Whoops.  That sentences has been munged.  It should have read

  BTW, -fallow-invalid-boz does NOT enable all previous broken
  usages of BOZ.

The missing NOT certainly changed the intent.  Again, historically
a BOZ was converted to an INTEGER(16) right after the BOZ was parsed.
This allowed a BOZ to appear anywhere an INTEGER(16) could appear.
There was an is_boz sentinel in the gfc_expr structure, but it was
only used in a few places.

Consider this piece of code

% cat a.f90
   print *, abs(z'4049abdf')
   end
% gfortran8 -o z a.f90  && ./z
           1078569951

In F2008 and later, a BOZ is a typeless string of bits without a
kind type parameter.  ABS() is a generic function.  Which specific
should be called?  It cannot be determined from the argument.  Now,
you get

% gfcx -c a.f90
a.f90:1:16:

    1 |    print *, abs(z'4049abdf')
      |                1
Error: 'a' argument of 'abs' intrinsic at (1) must have a numeric type

> In that case comparisons with BOZ should be allowed but they are not as
> indicated in my previous e-mail
> https://gcc.gnu.org/ml/fortran/2019-08/msg00031.html

BOZ are not allowed as an operand in an expression.  If you have
code that does

   if (i .eq. z'1234') ...

The correct way to write this is

   if (i .eq. int(z'1234')) ...

I thought about introducing -fbroken-boz option where the
gfortran source code would have had code that looked like

   if (flag_broken_boz)
     {
       old implementation used in gfortran 9 and older
     }
   else
     {
       new implementation
     }

There were two problems with this.  First, it would become a
maintenance nightmare of unmanagable code.  Second, users
would simply set -fbroken-boz as a default option and never
fix their codes, which then means the dual implementations
would both need to maintained forever.

--
Steve