diff mbox series

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

Message ID 20190723230520.GA33409@troutmask.apl.washington.edu
State New
Headers show
Series [Committed] PR fortran/54072 -- More fun with BOZ | expand

Commit Message

Steve Kargl July 23, 2019, 11:05 p.m. UTC
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  <kargl@gcc.gnu.org>

 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  <kargl@gcc.gnu.org>

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

Comments

Mark Eggleston Aug. 7, 2019, 12:58 p.m. UTC | #1
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  <kargl@gcc.gnu.org>
>
>   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  <kargl@gcc.gnu.org>
>
>   PR fortran/54072
>   * gfortran.dg/illegal_boz_arg_1.f90: New tests.
>
Steve Kargl Aug. 7, 2019, 4:09 p.m. UTC | #2
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 Kargl Aug. 7, 2019, 6:56 p.m. UTC | #3
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)

BTW, -fallow-invalid-boz does enable all previous broken 
usages of BOZ.  For example, BOZ can be an actual argument
in only a few intrinsic subprograms listed in F2018.  I've
allowed only a few exceptions such as AND(z'1234',4242)
which mirros IAND() is documented behavior. 

PS: Have you gotten write access to the source code repository, yet?
Mark Eggleston Aug. 8, 2019, 8:31 a.m. UTC | #4
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.

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

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

regards,

Mark

>    For example, BOZ can be an actual argument
> in only a few intrinsic subprograms listed in F2018.  I've
> allowed only a few exceptions such as AND(z'1234',4242)
> which mirros IAND() is documented behavior.
>
> PS: Have you gotten write access to the source code repository, yet?
>
Mark Eggleston Aug. 8, 2019, 9:11 a.m. UTC | #5
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
Steve Kargl Aug. 8, 2019, 2:44 p.m. UTC | #6
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 Kargl Aug. 8, 2019, 4:23 p.m. UTC | #7
On Thu, Aug 08, 2019 at 10:11:39AM +0100, Mark Eggleston wrote:
> 
> >> 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.

Because, I choose not to support invalid code.  One would need
to add a bunch of code to expr.c(simplify_intrinsic_op) to 
detect the BOZ usage and report an error or warning and then
do some conversion.  What does one do with

  if (z'12' .eq. z'4312')

Is this a hard error because both operands are BOZ?
Do you truncate the rhs operand or pad the lhs operand?
Do you simply convert these to INTEGER(16) and let the
compiler generate 128-bit integer code?

For the case

  if (i .eq. z'1234')  ! assuming i is integer

A conversion of the BOZ to the type and kind type of 'i' is possible.
Do we restrict the conversion to only rational operators?
Do we restrict the conversion to only integer comparisons?

What should this code do?

x = 4 * atan(1.) + 1
if (x .ge. z'40490FDB') print* , x
end

with gfortran 9, when compiled and executed it does not
produce output.

Should z'40490FDB' be converted to the type and kind of x?
In that case, gfortran-trunk would print out 4.14159...,
which is incompatiable with previous gfortran 9 and older. 
 
What should be done with unary operators?

i = - z'1234'  ! Assume i is integer.

The evaluation of the rhs is done first, and then assigned
to 'i' where possible conversion is done.

> 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.

Yes, fixing the code would be preferred.

> >> 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

Thanks,  I take a look at this.  It should be rejected.
Steve Kargl Aug. 8, 2019, 4:32 p.m. UTC | #8
On Thu, Aug 08, 2019 at 09:23:11AM -0700, Steve Kargl wrote:
> On Thu, Aug 08, 2019 at 10:11:39AM +0100, Mark Eggleston wrote:
> > 
> > >> 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.
> 
> Because, I choose not to support invalid code.  One would need
> to add a bunch of code to expr.c(simplify_intrinsic_op) to 
> detect the BOZ usage and report an error or warning and then
> do some conversion.  What does one do with

Ugh.  expr.c(simplify_intrinsic_op) would need updates if
we do some sort of constant-folding of BOZs.

For resolution of 'if (i .eq. z"123")'  one gets to 
resolve.c(resolve_operator).  The same questions still
apply.
diff mbox series

Patch

Index: gcc/fortran/check.c
===================================================================
--- gcc/fortran/check.c	(revision 273747)
+++ gcc/fortran/check.c	(working copy)
@@ -35,10 +35,10 @@  along with GCC; see the file COPYING3.  If not see
 #include "target-memory.h"
 
 /* A BOZ literal constant can appear in a limited number of contexts.
-   gfc_invalid_boz() is a help function to simplify error/warning generation.
-   Note, gfortran accepts the nonstandard 'X' for 'Z' the nonstandard
-   suffix location.  If -fallow-invalid-boz is used, then issue a warning;
-   otherwise issue an error.  */
+   gfc_invalid_boz() is a helper function to simplify error/warning
+   generation.  gfortran accepts the nonstandard 'X' for 'Z', and gfortran
+   allows the BOZ indicator to appear as a suffix.  If -fallow-invalid-boz
+   is used, then issue a warning; otherwise issue an error.  */
 
 bool
 gfc_invalid_boz (const char *msg, locus *loc)
@@ -54,6 +54,20 @@  gfc_invalid_boz (const char *msg, locus *loc)
 }
 
 
+/* Issue an error for an illegal BOZ argument.  */
+static bool
+illegal_boz_arg (gfc_expr *x)
+{
+  if (x->ts.type == BT_BOZ)
+    {
+      gfc_error ("BOZ literal constant at %L cannot be an actual argument "
+		 "to %qs", &x->where, gfc_current_intrinsic);
+      return true;
+    }
+
+  return false;
+}
+
 /* Some precedures take two arguments such that both cannot be BOZ.  */
 
 static bool
@@ -2202,8 +2216,6 @@  gfc_check_co_sum (gfc_expr *a, gfc_expr *result_image,
 bool
 gfc_check_complex (gfc_expr *x, gfc_expr *y)
 {
-
-  /* FIXME BOZ.  What to do with complex?  */
   if (!boz_args_check (x, y))
     return false;
 
@@ -5894,6 +5906,12 @@  gfc_check_transfer (gfc_expr *source, gfc_expr *mold, 
       return false;
     }
 
+  if (source->ts.type == BT_BOZ && illegal_boz_arg (source))
+    return false;
+
+  if (mold->ts.type == BT_BOZ && illegal_boz_arg (mold))
+    return false;
+
   /* MOLD shall be a scalar or array of any type.  */
   if (mold->ts.type == BT_PROCEDURE
       && mold->symtree->n.sym->attr.subroutine == 1)
@@ -7124,6 +7142,9 @@  gfc_check_storage_size (gfc_expr *a, gfc_expr *kind)
 		 gfc_current_intrinsic, &a->where);
       return false;
     }
+
+  if (a->ts.type == BT_BOZ && illegal_boz_arg (a))
+    return false;
 
   if (kind == NULL)
     return true;
Index: gcc/fortran/primary.c
===================================================================
--- gcc/fortran/primary.c	(revision 273747)
+++ gcc/fortran/primary.c	(working copy)
@@ -494,7 +494,6 @@  match_boz_constant (gfc_expr **result)
   e->boz.str = XCNEWVEC (char, length + 1);
   strncpy (e->boz.str, buffer, length);
 
-  /* FIXME BOZ.  */
   if (!gfc_in_match_data ()
       && (!gfc_notify_std(GFC_STD_F2003, "BOZ used outside a DATA "
 			  "statement at %L", &e->where)))
Index: gcc/testsuite/gfortran.dg/illegal_boz_arg_1.f90
===================================================================
--- gcc/testsuite/gfortran.dg/illegal_boz_arg_1.f90	(nonexistent)
+++ gcc/testsuite/gfortran.dg/illegal_boz_arg_1.f90	(working copy)
@@ -0,0 +1,9 @@ 
+! { dg-do compile }
+program foo
+   implicit none
+   integer :: i = 42
+   print *, storage_size(z'1234')     ! { dg-error "cannot be an actual" }
+   print *, transfer(z'1234', i)      ! { dg-error "cannot be an actual" }
+   print *, transfer(i, z'1234')      ! { dg-error "cannot be an actual" }
+   print *, transfer(i, i, z'1234')   ! { dg-error "must be INTEGER" }
+end program foo