[PATCH,fortran] Handle BOZ in accordance to Fortran 2018 standard

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

[PATCH,fortran] Handle BOZ in accordance to Fortran 2018 standard

Steve Kargl
I will be away until Monday.  Plenty of time for a review.

TL;DR version:

The attached patch fixes the handling of a BOZ literal constant
in gfortran to conform to the F2018 standard.

Long version:


  * No longer need to use -fno-range-check with BOZ
  * Fixed merge_bits
  * Eliminate a number of undocumented extension.
  * Added -fallow-invalid-boz option to allow BOZ in prohibited
    contexts.  This option is used by the new function gfc_invalid_boz,
    which issues an error for an invalid BOZ usage.  The option degrades
    the error to warning, and may allow the code to compile.  The
    result may not be what is expected based on older versions of
    gfortran (e.g., see FLOAT).  The warning can be suppressed with
    the -w option.
  * Deprecate the use of 'X' for an alias of 'Z'.
  * Deprecate postfix syntax (ie., '1234'z).

I believe the patch fixes all open PR's about BOZ with the
possible exception of PR88227.  PR88227 is a clever combination
of -m64 and/or -m32 with the -fdefault-* options.  It should be
well-known that IHMO the -fdefault-* option should be deprecated.
So, I don't care if this is fixed or not.

There is a long history of poor handling of a BOZ in the Fortran
standard.  In revision 95643 (2005-02-27) I made gfortran conform
to the Fortran 95 standard's definition of a BOZ in a DATA statement
(which is the only context in which a BOZ can appear in a conforming
Fortran 95 program).  This is tantamount to converting a BOZ to the
widest available INTEGER on a target (i.e., INTEGER(8) or INTEGER(16))
when the BOZ is initially parsed.  This has the effect that a BOZ may
appear in any context where a integer literal constant may appear.
Gfortran contains a boat load of undocumented extensions.  The patch
removes most of these undocumented extensions (i.e., an error will
be issued).

In F2008 and F2018, a BOZ is a ***typeless*** string of bits, which
does not have a kind type parameter.  When the string of bits is to
be converted to some quantity, a few things can happen.  If it is
too short, the string is padded with zeros.  If it is too long, it
is truncated.  The handling of the sign bit is processor dependent.
I have introduced 2 functions in check.c (gfc_boz2int and gfc_boz2real)
to handle the conversion.  gfc_boz2int essentially converts a BOZ
into an unsigned integer, and then does two-complements wrap-around
to obtain negative values.  gfc_boz2real does the padding/truncation
as needed and then converts that BOZ into an intermediate widest
INTEGER, which is given to gfc_convert_boz in target-memory.c to
do the actual conversion to a REAL.  Range checking has been removed
in gfc_convert_boz.

Along the way, I have deprecated the SHORT and LONG aliases for
INT(x,2) and INT(x,4).  The primary reason for deprecation is that
LONG is documented to convert its argument to a C long.  Well, the
size of a C long depends on the target.

The code for deprecated items is still present and can sometimes
be used via the -fallow-invalid-boz option.  After 10.1 is released,
and if I am still contributing to gfortran, I will remove the code.
If someone feels strongly that a previous undocument extension
should be retain, feel free to fix it after I commit the patch.
I think I've weighed the pros and cons, and have made prudent
decision of want to deprecate.

Finally, I will only respond to technical questions/comments.
Any non-technical questions/comments will be forwarded to /dev/null.

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

        * arith.c (gfc_convert_integer, gfc_convert_real, gfc_convert_complex):
        Move to ...
        * primary.c (convert_integer, convert_real, convert_complex): ... here.
        Rename and make static functions.
        (match_integer_constant): Use convert_integer
        (match_real_constant): Use convert_real.
        (match_complex_constant: Use convert_complex.
        * arith.h (gfc_convert_integer, gfc_convert_real, gfc_convert_complex):
        Remove prototypes.
        * array.c (match_array_cons_element): A BOZ cannot be a data
        statement value.  Jump to a common exit point.
        * check.c (gfc_invalid_boz): New function.  Emit error or warning
        for a BOZ in an invalid context.
        (boz_args_check): Move to top of file to prevent need of forward
        (is_boz_constant): New function.  Check that BOZ expr is constant.
        (gfc_boz2real): New function. In-place conversion of BOZ literal
        constant to REAL in accordance to F2018.
        (gfc_boz2int): New function. In-place conversion of BOZ literal
        constant to INTEGER in accordance to F2018.
        (gfc_check_achar, gfc_check_char, gfc_check_float): Use
        gfc_invalid_boz.  Convert BOZ as needed.
        (gfc_check_bge_bgt_ble_blt): Enforce F2018 requirements on BGE,
        BGT, BLE, and BLT intrinsic functions.
        (gfc_check_cmplx): Re-organize to check kind, if present, first.
        Convert BOZ real and/or imaginary parts as needed in accordance to
        (gfc_check_complex):  Use gfc_invalid_boz.  Convert BOZ as needed.
        (gfc_check_dcmplx, gfc_check_dble ): Convert BOZ as needed.
        (gfc_check_dshift):  Make dshift[lr] conform to F2018 standard.
  gfc_check_float (gfc_expr *a)
        (gfc_check_iand_ieor_ior):  Make IAND, IEOR, and IOR conform to
        F2018 standard.
        (gfc_check_int): Conform to F2018 standard.
        (gfc_check_intconv): Deprecate SHORT and LONG aliases for INT2 and
        INT.  Simply return for a BOZ argument. See gfc_simplify_intconv.
        (gfc_check_merge_bits): Make MERGE_BITS conform to Fortran 2018
        (gfc_check_real): Remove incorrect comment. Check kind, if present,
        first.  Simply return for a BOZ argument. See gfc_simplify_real.
        (gfc_check_and): Re-do error handling for BOZ arguments.  Remove
        special casing ts.type != BT_INTEGER or BT_LOGICAL.
        * decl.c (match_old_style_init): Check for BOZ in old-style
        initialization.  Issue error or warning depending on
        -fallow-invalid-boz option.  Issue error if variable is not an
        INTEGER or REAL and the value is BOZ.
        * expr.c (gfc_copy_expr): Copy a BT_BOZ gfc_expr.
        (gfc_check_assign): Re-do error handling for a BOZ in an assignment
        statement.  Do in-place conversion of RHS based on LHS type of
        INTEGER or REAL.
        * gfortran.h (gfc_expr): Add a boz component.  Remove is_boz component.
        (gfc_boz2int, gfc_boz2real, gfc_invalid_boz): New prototypes.
        * interface.c (gfc_extend_assign): Guard against replacing an
        intrinsic involving a BOZ literal constant on RHS.
        * invoke.texi: Doument -fallow-invalid-boz.
        * lang.opt: New option. -fallow-invalid-boz.
        * libgfortran.h (bt): Elevate BOZ to a basic type.
        * misc.c (gfc_basic_typename, gfc_typename): Translate BT_BOZ to BOZ.
        * primary.c (convert_integer, convert_real, convert_complex): to here.
        Rename and make static functions.
        * primary.c(match_boz_constant): Rewrite parsing of a BOZ. Re-do
        error handling.  Deprecate 'X' for hexidecimal and postfix notation.
        Use -fallow-invalid-boz and gfc_invalid_boz to accept deprecated code.
        * resolve.c (resolve_ordinary_assign): Rework a RHS that is a
        BOZ literal constant.  Use gfc_invalid_boz to allow previous
        nonstandard behavior.  Remove range checking of BOZ conversion.
        * simplify.c (convert_boz): Remove function.
        (simplify_cmplx): Remove conversion of BOZ constants, because
        conversion is done in gfc_check_cmplx.
        (gfc_simplify_float): Remove conversion of BOZ constant, because
        conversion is done in gfc_check_float.
        (simplify_intconv): Use gfc_boz2int to convert BOZ to INTEGER.
        Remove range checking for BOZ conversion.
        (gfc_simplify_real): Use k, if present, to determine kind.  Convert
        BOZ to REAL.  Remove range checking for BOZ conversion.
        target-memory.c (gfc_convert_boz): Rewrite to deal with convert of
        a BOZ to a REAL value.

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

        * gfortran.dg/achar_5.f90: Fix for new BOZ handling.
        * arithmetic_overflow_1.f90: Ditto.
        * gfortran.dg/boz_11.f90: Ditto.
        * gfortran.dg/boz_12.f90: Ditto.
        * gfortran.dg/boz_4.f90: Ditto.
        * gfortran.dg/boz_5.f90: Ditto.
        * gfortran.dg/boz_6.f90: Ditto.
        * gfortran.dg/boz_7.f90: Ditto.
        * gfortran.dg/boz_8.f90: Ditto.
        * gfortran.dg/dec_structure_6.f90: Ditto.
        * gfortran.dg/dec_union_1.f90: Ditto.
        * gfortran.dg/dec_union_2.f90: Ditto.
        * gfortran.dg/dec_union_5.f90: Ditto.
        * gfortran.dg/dshift_3.f90: Ditto.
        * gfortran.dg/gnu_logical_2.f90: Ditto.
        * gfortran.dg/int_conv_1.f90: Ditto.
        * gfortran.dg/ishft_1.f90: Ditto.
        * gfortran.dg/nan_4.f90: Ditto.
        * gfortran.dg/no_range_check_3.f90: Ditto.
        * gfortran.dg/pr16433.f: Ditto.
        * gfortran.dg/pr44491.f90: Ditto.
        * gfortran.dg/pr58027.f90: Ditto.
        * gfortran.dg/pr81509_2.f90: Ditto.
        * gfortran.dg/unf_io_convert_1.f90: Ditto.
        * gfortran.dg/unf_io_convert_2.f90: Ditto.
        * gfortran.fortran-torture/execute/intrinsic_fraction_exponent.f90:
        * gfortran.fortran-torture/execute/intrinsic_mvbits.f90: Ditto.
        * gfortran.fortran-torture/execute/intrinsic_nearest.f90: Ditto.
        * gfortran.fortran-torture/execute/seq_io.f90: Ditto.
        * gfortran.dg/gnu_logical_1.F: Delete test.
        * gfortran.dg/merge_bits_3.f90: New test.
        * gfortran.dg/merge_bits_3.f90: Ditto.
        * gfortran.dg/boz_int.f90: Ditto.
        * gfortran.dg/boz_bge.f90: Ditto.
        * gfortran.dg/boz_complex_1.f90: Ditto.
        * gfortran.dg/boz_complex_2.f90: Ditto.
        * gfortran.dg/boz_complex_3.f90: Ditto.
        * gfortran.dg/boz_dble.f90: Ditto.
        * gfortran.dg/boz_dshift_1.f90: Ditto.
        * gfortran.dg/boz_dshift_2.f90: Ditto.
        * gfortran.dg/boz_float_1.f90: Ditto.
        * gfortran.dg/boz_float_2.f90: Ditto.
        * gfortran.dg/boz_float_3.f90: Ditto.
        * gfortran.dg/boz_iand_1.f90: Ditto.
        * gfortran.dg/boz_iand_2.f90: Ditto.

Bootstrapped on i585-*-freebsd and x86_64-*-freebsd.  No regressions
after fixing all the nonstandard code in the testsuite. :-)

Ok to commit?

20170425 https://www.youtube.com/watch?v=VWUpyCsUKR4
20161221 https://www.youtube.com/watch?v=IbCHE-hONow

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

Re: [PATCH,fortran] Handle BOZ in accordance to Fortran 2018 standard

Steve Kargl
On Sat, Jul 20, 2019 at 10:12:07AM -0700, Jerry DeLisle wrote:

> On 7/17/19 8:32 PM, Steve Kargl wrote:
> > I will be away until Monday.  Plenty of time for a review.
> >
> >
> ---snip --
> Something not quite right here in this comment.
> +/* 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
>                                                        ^<<< in >>?
> +   suffix location.  If -fallow-invalid-boz is used, then issue a warning;
> +   otherwise issue an error.  */

Whoops forgot to fix this before committing.  I'll fix shortly.

> +  /* FIXME BOZ.  What to do with complex?  */
> Is your question here regarding whether to treat the two real storage locations
> as one single area and pad? Or to duplicate one BOZ pattern into each? Or
> require two BOZ patterns to be provided? or something else?

Old comment.  I remove shortly.  The issue center arounds
complex(z'1234',z'4567').  This is now rejected as there is
no information on how to convert the BOZ.

> --- snip ---
> -
> +  /* FIXME BOZ.  */
>     if (!gfc_in_match_data ()
>         && (!gfc_notify_std(GFC_STD_F2003, "BOZ used outside a DATA "
> -  "statement at %C")))
> -      return MATCH_ERROR;
> +  "statement at %L", &e->where)))
> +    return MATCH_ERROR;
> Maybe expand the comment a bit to better hint at the issue.

Whoops. Again, committed before fixing.  I'll update shortly.

> --- snip ---
> The patch applies cleanly and tests OK on my machines here. I am very much in
> favor of deprecating LONG and SHORT which are way too ambiguous.
> I say OK to commit.

Thanks.  Committed.