Bug 29471 - Warn with -std=f95/f2003 when BOZ is used at invalid places
Summary: Warn with -std=f95/f2003 when BOZ is used at invalid places
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: unknown
: P3 enhancement
Target Milestone: 4.3.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-10-14 19:20 UTC by tobias.burnus
Modified: 2007-12-11 23:15 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2007-08-12 20:10:32


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description tobias.burnus 2006-10-14 19:20:05 UTC
gfortran allows everywhere to use a BOZ.

However, there are constrains in Fortran 95 and 2003 on where to use them.

- Fortran 95: Only in DATA and only integer
- Fortran 2003: Only in DATA or as argument of INT, REAL, DBLE, CMPLX

Expected: An ERROR (or WARNING) is shown, when -std=f95/f2003 is used.

Fortran 95:
"R407 boz-literal-constant [...]
Constraint: A boz-literal-constant may appear only in a DATA statement.[...]
If a data-statement-constant is a boz-literal-constant, the corresponding object shall be of type integer."

Fortran 2003:
"C410 (R411) A boz-literal-constant shall appear only as a data-stmt-constant in a DATA statement, as the actual argument associated with the dummy argument A of the numeric intrinsic functions DBLE, REAL or INT, or as the actual argument associated with the X or Y dummy argument of the intrinsic function CMPLX."
Comment 1 tobias.burnus 2006-10-16 13:34:37 UTC
Note that there is a change in meaning:

BOZ-everywhere extension:
   a = real(z'F')
is the same as  real(int(z'F')) = 15.0
(This is what gfortran does and Intel does by default)

Fortran 2003:
   a = real(z'F')
= 2.1019477E-44


Intel gives a default warning in such cases:

fortcom: Warning: boz2.f90, line 2: The Fortran 2003 Standard will use this bit pattern directly and NOT convert it to REAL as if it were an INTEGER constant (try -switch fe_new_BOZ_constants).
   a = real(z'F')
------------^
Comment 2 kargl 2006-10-16 16:51:44 UTC
This is going to be difficult to fix.  In fact, it will require a
complete rewrite on how BOZ are handled.

> Fortran 2003:
>   a = real(z'F')
>     = 2.1019477E-44

Are you sure this is the only correct value?  The F2003 says nothing
about the other 28 bits.  It also says nothing about whether z'F'
applies to most significant bits or least significant bits of the
32-bit real.
Comment 3 tobias.burnus 2006-10-16 17:12:45 UTC
(In reply to comment #2)
> > Fortran 2003:
> >   a = real(z'F')
> >     = 2.1019477E-44
> 
> Are you sure this is the only correct value?  The F2003 says nothing
> about the other 28 bits.  It also says nothing about whether z'F'
> applies to most significant bits or least significant bits of the
> 32-bit real.

Well, that is the value ifort gave me (using "-switch fe_new_BOZ_constants"); I think it is a valid value, but I'm not sure whether it is the only one.

As NAG f95, g95 and sunf95 do not yet support F2003's BOZ, I cannot compare with what they give. I also found the F2003 standard not so detailed, but maybe I missed the right spot. Best to ask at comp.lang.fortran.
Comment 4 kargl 2006-10-16 17:23:41 UTC
Forgot to add myself to cc listing.

Tobias, the only place the handling on a BOZ (other the data-stmt handling)
is discussed in the description REAL() intrinsic procedure.  It contains
the dreaded "processor-dependent" language.
Comment 5 Joe Krahn 2007-03-16 03:46:29 UTC
BOZ processing was recently broken in gfortran. I assume it relates to the issues here.

The current problem is shown in this bit of code:

  write(*,*)'NaN(8)=',real(z'FFF8000000000000',8)
  end

gfortran, even with -std=f2003, claims that the BOZ data is too big. Apparently, it is first converting to an UNSIGNED integer, then trying to cast to a SIGNED Fortran integer. With F2003, this form of BOZ should do a 'reinterpret-cast' of raw binary bits directly to the destination type.

Even without the reinterpret cast problem, integer BOZ is not handled correctly. This expression also claims the BOZ is too large:
   int(z'FFFFFFFFFFFFFFFF',8)

Again, it is being intepreted as an UNSIGNED int then static-cast to a signed in, thus overflowing.

The traditional behavior is for all BOZ to be initially interpreted as the largets integer type supported. As usual with Fortran, that is a horrible definition. In order to define a -1 BYTE, you have to write out the whole 8-bytes worth of FF. Intel seems to use a sane (but nonstandard) method that appears to interpret initially as the smallest type that contains all of the bits specified.

F95 dropped BOZ because of the lame definition, but F2003 brought it back for use mainly within REAL() and INT(), which allow the raw initial interpretation in a sensible way.

The only hassle with "processor dependent" definitions is that the result of a given binary value depends on a processor's internal binary format. So, IEEE floats are portable, but other long/quad real numbers are not. In any case, it comes down to a raw binary value converted directly to the destination for the F2003 forms.

For the older form, which is still the case in F2003 for DATA statements, it is hard to know whether to 'cheat' and allow z'FF' to define a -1 byte, or stick to the strict messed-up definition. What did G77 do?

A related problem is that I am trying to create a NaN constant (parameter). I can't use REAL+BOZ, but I also cannot define "real :: NaN = 0.0/0.0". In this case, divide-by-zero is invalid math, but should only be a warning and not an error. (I am speaking practically; I don't know what the standards say.)

But, good news, I just discovered that this hack works:
  NaN = transfer(ishft(int(z'FFF80000',8),32),0.0_8)

I tried that a while back with gfortran and it crashed. What we really need is a NAN(kind=8) intrinsic.
Comment 6 Joe Krahn 2007-03-16 03:53:57 UTC
One more comment: I just checked the INT() intrisic for F2003. It actually still states that a BOZ is initially interpreted as the largest integer type (ugh!) REAL() has the correct definition of interpreting as the target REAL kind. I have to assume that they think a LARGE integer will hold all BOZ values, and can simply be down-cast. Could they actually have forgotten about negative values?!?

I have not checked F2008 yet. My vote is to just ignore the standards when it comes to negative BOZ, the way Intel has done it, which I HOPE is what F2008 says.

Comment 7 Steve Kargl 2007-03-16 04:07:34 UTC
Subject: Re:  Warn with -std=f95/f2003 when BOZ is used at invalid places

On Fri, Mar 16, 2007 at 03:46:30AM -0000, jkrahn at nc dot rr dot com wrote:
> 
> 
> ------- Comment #5 from jkrahn at nc dot rr dot com  2007-03-16 03:46 -------
> BOZ processing was recently broken in gfortran.

No, it was fixed.

> I assume it relates to the issues here.
> 
> The current problem is shown in this bit of code:
> 
>   write(*,*)'NaN(8)=',real(z'FFF8000000000000',8)
>   end
> 
> gfortran, even with -std=f2003, claims that the BOZ data is too big.

Do you have an INTEGER(16)?

> Apparently, it is first converting to an UNSIGNED integer, then trying to cast
> to a SIGNED Fortran integer.

Not even close to the truth.

> With F2003, this form of BOZ should do a
> 'reinterpret-cast' of raw binary bits directly to the destination type.

gfortran implements the F95 behavior and extensions.  The extension
conflict with F2003.

> Even without the reinterpret cast problem, integer BOZ is not handled
> correctly. This expression also claims the BOZ is too large:
>    int(z'FFFFFFFFFFFFFFFF',8)

Do you have INTEGER(16)?

> Again, it is being intepreted as an UNSIGNED int then static-cast to a signed
> in, thus overflowing.


Not even close to the truth.

> The traditional behavior is for all BOZ to be initially interpreted as the
> largets integer type supported.

Do you have an INTEGER(16)?

> F95 dropped BOZ because of the lame definition

Huh?

> but F2003 brought it back for use mainly within REAL() and INT(),
> which allow the raw initial interpretation in a sensible way.

No, it isn't sensible.  It is *processor dependent*.  Think big
versus little endian to start.  Next consider that F2003 does not
define the underlying floating representation.  This was a very
broken attempt to fix TRANSFER.

> A related problem is that I am trying to create a NaN constant (parameter). I
> can't use REAL+BOZ, but I also cannot define "real :: NaN = 0.0/0.0". In this
> case, divide-by-zero is invalid math, but should only be a warning and not an
> error. (I am speaking practically; I don't know what the standards say.)

program rtfm
x = 0. / 0.
end program rtfm

gfc -fno-range-check -o z rtfm.f90

Comment 8 Steve Kargl 2007-03-16 04:09:05 UTC
Subject: Re:  Warn with -std=f95/f2003 when BOZ is used at invalid places

On Fri, Mar 16, 2007 at 03:53:57AM -0000, jkrahn at nc dot rr dot com wrote:
>
> I have not checked F2008 yet. My vote is to just ignore the standards when it
> comes to negative BOZ, the way Intel has done it, which I HOPE is what F2008
> says.

gfortran doesn't have that luxury.  it can't ignore the standard.

Comment 9 Tobias Burnus 2007-03-16 09:45:28 UTC
> The current problem is shown in this bit of code:
>   write(*,*)'NaN(8)=',real(z'FFF8000000000000',8)
>   end

Note: gfortran does not support Fortran 2003 BOZ yet.

> gfortran, even with -std=f2003, claims that the BOZ data is too big.
Use -fno-range-check to disable this checking. But this will still the old BOZ extension and not the Fortran 2003 BOZ.

> Even without the reinterpret cast problem, integer BOZ is not handled
> correctly. This expression also claims the BOZ is too large:
>    int(z'FFFFFFFFFFFFFFFF',8)

The number is does not fit into -huge(1_8) ... huge(1_8) and is therefore outside of the Fortran standard. -> -fno-range-check

> The traditional behavior is for all BOZ to be initially interpreted as the
> largets integer type supported.

Which is why gfortran gives no error if you use int(BOZ, kind=16).

> The only hassle with "processor dependent" definitions is that the result of a
> given binary value depends on a processor's internal binary format. So, IEEE
> floats are portable, but other long/quad real numbers are not.
"Processor dependent" in the Fortran language does not only mean the CPU but also the compiler; nonetheless, in this regard most (all?) compilers produce the same result on a given platform.

> A related problem is that I am trying to create a NaN constant (parameter). I
> can't use REAL+BOZ, but I also cannot define "real :: NaN = 0.0/0.0". In this
> case, divide-by-zero is invalid math, but should only be a warning and not an
> error. (I am speaking practically; I don't know what the standards say.)

The standard does not say anything about non-Fortran numbers. Fortran 2003 has now support of the IEEE arithmetics, which allows NaN, denormalized numbers and +/-INF, overflowing etc.

Thus for a Fortran 95 compiler, the 0./0. can always be rejected, whereas for Fortran 2003 it is a bit unclearer (cf. below for a standard way to get Nan).

my personal trick is to use:
 real :: r, NaN
 r = 0.0
 NaN = 0.0/r
which does the NaN at run time. (You still need to have the right compiler flags as otherwise you get an arithmetic exception at run time.)

> But, good news, I just discovered that this hack works:
>   NaN = transfer(ishft(int(z'FFF80000',8),32),0.0_8)
> I tried that a while back with gfortran and it crashed.

A modified version still crashes with gfortran:
  real(kind(0d0)) :: NaN = transfer(ishft(int(z'FFF80000',8),32),0d0)
  print *, NaN
Interestingly, this produces "0.0" with ifort, while g95 and sunf95 give "NaN".
See PR 31194.

> What we really need is a NAN(kind=8) intrinsic.

Well, one can do in Fortran 2003:
 use,intrinsic :: ieee_arithmetic
 real :: NaN
 NaN = ieee_value(x,ieee_quiet_nan)

(Note: IEEE arithmetic is not yet supported by many compilers, especially gfortran does not support it yet.)

(In reply to comment #6)
> My vote is to just ignore the standards when it
> comes to negative BOZ, the way Intel has done it, which I HOPE is what F2008
> says.

Sorry, I think most people would like to have a standard conform compiler; we cannot do so.

Besides IEEE arithmetic allows what you want. Using transfer is a non-portable way to do so, which assumes a certain internal structure. And using your integer BOZ are supported with -fno-range-check.
Comment 10 Tobias Burnus 2007-12-08 21:47:20 UTC
Subject: Bug 29471

Author: burnus
Date: Sat Dec  8 21:46:56 2007
New Revision: 130713

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=130713
Log:
2007-12-08  Tobias Burnus  <burnus@net-b.de>

        PR fortran/34342
        PR fortran/34345
        PR fortran/18026
        PR fortran/29471

        * gfortran.texi (BOZ literal constants): Improve documentation
        and adapt for BOZ changes.
        * Make-lang.ini (resolve.o): Add target-memory.h dependency.
        * gfortran.h (gfc_expr): Add is_boz flag.
        * expr.c: Include target-memory.h.
        (gfc_check_assign): Support transferring BOZ for real/cmlx.
        * resolve.c: Include target-memory.h
        (resolve_ordinary_assign): Support transferring BOZ for real/cmlx.
        * target-memory.c (gfc_convert_boz): New function.
        * target-memory.c (gfc_convert_boz): Add prototype.
        * primary.c (match_boz_constant): Set is_boz, enable F95 error
        also without -pedantic, and allow for Fortran 2003 BOZ.
        (match_real_constant): Fix comment.
        * simplify.c
        * (simplify_cmplx,gfc_simplify_dble,gfc_simplify_float,
        gfc_simplify_real): Support Fortran 2003 BOZ.

2007-12-08  Tobias Burnus  <burnus@net-b.de>

        PR fortran/34342
        PR fortran/34345
        PR fortran/18026
        PR fortran/29471

        * gfortran.dg/boz_8.f90: New.
        * gfortran.dg/boz_9.f90: New.
        * gfortran.dg/boz_10.f90: New.
        * gfortran.dg/boz_7.f90: Update dg-warning.
        * gfortran.dg/pr16433.f: Add dg-error.
        * gfortan.dg/ibits.f90: Update dg-warning.
        * gfortran.dg/unf_io_convert_1.f90: Update/delete dg-warning.
        * gfortran.dg/unf_io_convert_2.f90: Ditto.


Added:
    trunk/gcc/testsuite/gfortran.dg/boz_10.f90
    trunk/gcc/testsuite/gfortran.dg/boz_8.f90
    trunk/gcc/testsuite/gfortran.dg/boz_9.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/Make-lang.in
    trunk/gcc/fortran/expr.c
    trunk/gcc/fortran/gfortran.h
    trunk/gcc/fortran/gfortran.texi
    trunk/gcc/fortran/primary.c
    trunk/gcc/fortran/resolve.c
    trunk/gcc/fortran/simplify.c
    trunk/gcc/fortran/target-memory.c
    trunk/gcc/fortran/target-memory.h
    trunk/gcc/testsuite/ChangeLog
    trunk/gcc/testsuite/gfortran.dg/boz_7.f90
    trunk/gcc/testsuite/gfortran.dg/ibits.f90
    trunk/gcc/testsuite/gfortran.dg/pr16433.f
    trunk/gcc/testsuite/gfortran.dg/unf_io_convert_1.f90
    trunk/gcc/testsuite/gfortran.dg/unf_io_convert_2.f90

Comment 11 Tobias Burnus 2007-12-08 22:08:43 UTC
FIXED on the trunk (4.3.0).

> Fortran 95: Only in DATA and only integer
> Fortran 2003: Only in DATA or as argument of INT, REAL, DBLE, CMPLX

Fortran 2003 BOZ are now properly supported.

For -std=f95 full diagnostics exist, however, for -std=f2003 gfortran allows BOZ also at invalid places, see PR 34392.

For the supported BOZ extensions, see also:
http://gcc.gnu.org/onlinedocs/gfortran/BOZ-literal-constants.html

(Wait a day until that page is up to date.)
Comment 12 Tobias Burnus 2007-12-08 22:09:45 UTC
Mark really as FIXED.
Comment 13 Joe Krahn 2007-12-11 19:40:17 UTC
My previous post here was a bit confused by differences in F95 and F2003, and my misunderstanding of Gfortran's BOZ extension.

As I understand the F2003 standard, the expression "INT(z'ff',1)" should produce a range error, for the same reasons as the data statement illustrated in:
http://gcc.gnu.org/onlinedocs/gfortran/BOZ-literal-constants.html
In practice, I don't think any compilers do this (yet).

I thought that F2003 allowed this type of BOZ usage because the KIND was well defined, because the F2003 (draft) standard gives the rule for interpretation as the largest integer kind with DATA statements, but not under REAL(), DBLE(), or CMPLX(). However, I just checked again and found that INT() does require the initial interpretation as the largest integer kind. Unless the final standard differs, it appears that interpretation of BOZ for REAL(), etc., are completely undefined. As far as I can tell, it would be equally valid to interpret a hex value as a binary real value, or just to convert as with integer assignment.

Due to being ill-defined, I suggested ignoring the standard. Instead, the right suggestion is an extension which modifies the standard. Maybe there should be a "-f[no-]boz-range-check" to exclude range errors just for the BOZ case. Also, to avoid misleading users into thinking that F2003 BOZ are well-defined, it might be good to warn about any BOZ usage, maybe as part of "-Wsurprising".

F2008 draft, it re-defines B/O/Z literals, named BITS instead of BOZ. It seems to be an improvement, but will probably add to the difficulty of supporting multiple standards. 
Comment 14 Tobias Burnus 2007-12-11 23:15:14 UTC
> As I understand the F2003 standard, the expression "INT(z'ff',1)" should
> produce a range error, for the same reasons as the data statement illustrated
> in:
> http://gcc.gnu.org/onlinedocs/gfortran/BOZ-literal-constants.html
> In practice, I don't think any compilers do this (yet).

Well, I am not sure whether the compiler is required to do so; with some BOZ work, I disabled accidentally some range checks (see PR 34398), but your INT gives an error with gfortran:

print *, INT(z'ff',1)
            1
Error: Result of INT overflows its kind at (1)

(Note: the value "1" is a (common) implementation choice; not every compiler has kind = byte size.)


> Maybe there should be a "-f[no-]boz-range-check" to exclude range errors just
> for the BOZ case.
I think -fno-range-check should be enough for both, shouldn't it?


> F2008 draft, it re-defines B/O/Z literals, named BITS instead of BOZ.
That part got dropped, see 13 August at:
http://www.nag.co.uk/sc22wg5/
Comment 15 Joe Krahn 2007-12-12 01:04:20 UTC
Subject: Re:  Warn with -std=f95/f2003 when BOZ is used
 at invalid places

burnus at gcc dot gnu dot org wrote:
...
>> Maybe there should be a "-f[no-]boz-range-check" to exclude range errors just
>> for the BOZ case.
> I think -fno-range-check should be enough for both, shouldn't it?
My feeling is that BOZ range errors will occur often due to a poorly
designed spec, but that other range errors may really be bugs.
Alternatively, it might be good to a define BOZ mode flag, especially
since gfortran already supports a non-standard extension, and because
the vague standard means that there will be differences among compilers.

> 
>> F2008 draft, it re-defines B/O/Z literals, named BITS instead of BOZ.
> That part got dropped, see 13 August at:
> http://www.nag.co.uk/sc22wg5/
> 
Well, I hope that they at least update the BOZ specification.