diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 5e1dba93435..59cfa32297a 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,12 @@ +2012-05-14 Janne Blomqvist + + PR fortran/52428 + * gfortran.texi: Update _gfortran_set_options documentation. + * invoke.texi: Remove runtime behavior description of + -fno-range-check. + * trans-decl.c (create_main_function): Don't pass the range-check + setting to the library. + 2012-05-14 Tobias Burnus PR fortran/49110 diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi index 96662c49423..ffcd3ece2d7 100644 --- a/gcc/fortran/gfortran.texi +++ b/gcc/fortran/gfortran.texi @@ -2740,15 +2740,13 @@ Default: enabled. are (bitwise or-ed): GFC_RTCHECK_BOUNDS (1), GFC_RTCHECK_ARRAY_TEMPS (2), GFC_RTCHECK_RECURSION (4), GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32). Default: disabled. -@item @var{option}[7] @tab If non zero, range checking is enabled. -Default: enabled. See -frange-check (@pxref{Code Gen Options}). @end multitable @item @emph{Example}: @smallexample - /* Use gfortran 4.7 default options. */ - static int options[] = @{68, 511, 0, 0, 1, 1, 0, 1@}; - _gfortran_set_options (8, &options); + /* Use gfortran 4.8 default options. */ + static int options[] = @{68, 511, 0, 0, 1, 1, 0@}; + _gfortran_set_options (7, &options); @end smallexample @end table diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi index 8db869bfa68..658ed2375fc 100644 --- a/gcc/fortran/invoke.texi +++ b/gcc/fortran/invoke.texi @@ -166,8 +166,7 @@ and warnings}. @item Runtime Options @xref{Runtime Options,,Options for influencing runtime behavior}. -@gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length} --fno-range-check @gol +@gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length} @gol -frecord-marker=@var{length} -fsign-zero } @@ -1116,16 +1115,6 @@ representation for unformatted files. The @code{CONVERT} specifier and the GFORTRAN_CONVERT_UNIT environment variable override the default specified by @option{-fconvert}.} - -@item -fno-range-check -@opindex @code{fno-range-check} -Disable range checking of input values during integer @code{READ} operations. -For example, GNU Fortran will give an error if an input value is -outside of the relevant range of [@code{-HUGE()}:@code{HUGE()}]. In other words, -with @code{INTEGER (kind=4) :: i} , attempting to read @math{-2147483648} will -give an error unless @option{-fno-range-check} is given. - - @item -frecord-marker=@var{length} @opindex @code{frecord-marker=}@var{length} Specify the length of record markers for unformatted files. diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 1354ad05e3d..0480f956c84 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -5039,12 +5039,17 @@ create_main_function (tree fndecl) build_int_cst (integer_type_node, (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS))); + /* TODO: This is the -frange-check option, which no longer affects + library behavior; when bumping the library ABI this slot can be + reused for something else. As it is the last element in the + array, we can instead leave it out altogether. CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, build_int_cst (integer_type_node, gfc_option.flag_range_check)); + */ array_type = build_array_type (integer_type_node, - build_index_type (size_int (7))); + build_index_type (size_int (6))); array = build_constructor (array_type, v); TREE_CONSTANT (array) = 1; TREE_STATIC (array) = 1; @@ -5059,7 +5064,7 @@ create_main_function (tree fndecl) tmp = build_call_expr_loc (input_location, gfor_fndecl_set_options, 2, - build_int_cst (integer_type_node, 8), var); + build_int_cst (integer_type_node, 7), var); gfc_add_expr_to_block (&body, tmp); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c160fae1530..d6a2adfe77d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-05-14 Janne Blomqvist + + PR fortran/52428 + * gfortran.dg/int_range_io_1.f90: New test. + 2012-05-14 Andi Kleen Jakub Jelinek diff --git a/gcc/testsuite/gfortran.dg/int_range_io_1.f90 b/gcc/testsuite/gfortran.dg/int_range_io_1.f90 new file mode 100644 index 00000000000..de1fdb81304 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/int_range_io_1.f90 @@ -0,0 +1,34 @@ +! { dg-do run } +! { dg-options "-fno-range-check" } +! PR 52428 Read IO of integers near the end of range. Note that we +! support the two's complement representation even though the Fortran +! numerical model has a symmetric range. (The -fno-range-check option +! is needed to allow the -2147483648 literal.) +program int_range + implicit none + character(25) :: inputline = "-2147483648" + integer(4) :: test + integer :: st + + read(inputline,100) test +100 format(1i11) + if (test /= -2147483648) call abort + inputline(1:1) = " " + read(inputline, 100, iostat=st) test + if (st == 0) call abort + inputline(11:11) = "7" + read(inputline, 100) test + if (test /= 2147483647) call abort + + ! Same as above but with list-formatted IO + inputline = "-2147483648" + read(inputline, *) test + if (test /= -2147483648) call abort + inputline(1:1) = " " + read(inputline, *, iostat=st) test + if (st == 0) call abort + inputline(11:11) = "7" + read(inputline, *) test + if (test /= 2147483647) call abort + +end program int_range diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index a6223fc24c3..088d51786d7 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,20 @@ +2012-05-14 Janne Blomqvist + + PR fortran/52428 + * io/io.h (max_value): Rename to si_max, remove second argument. + * io/list_read.c (convert_integer): Use unsigned types when + parsing the digits, set max value depending on the sign. + * io/read.c (max_value): Rename to si_max, remove second argument, + simplify. + (read_decimal): Set max value depending on sign, always check + overflow. + (read_radix): Calculate max unsigned value directly. + * libgfortran.h (struct compile_options_t): Remove range_check + field. + * runtime/compile_options.c (set_options): Skip handling + options[7]. + (init_compile_options): Don't set removed field. + 2012-05-11 Tobias Burnus PR fortran/53310 diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h index 06364e17b2c..6b54af18362 100644 --- a/libgfortran/io/io.h +++ b/libgfortran/io/io.h @@ -661,8 +661,8 @@ internal_proto(hit_eof); extern void set_integer (void *, GFC_INTEGER_LARGEST, int); internal_proto(set_integer); -extern GFC_UINTEGER_LARGEST max_value (int, int); -internal_proto(max_value); +extern GFC_UINTEGER_LARGEST si_max (int); +internal_proto(si_max); extern int convert_real (st_parameter_dt *, void *, const char *, int); internal_proto(convert_real); diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c index 4d2ce794120..b0c4e5fca52 100644 --- a/libgfortran/io/list_read.c +++ b/libgfortran/io/list_read.c @@ -461,12 +461,20 @@ convert_integer (st_parameter_dt *dtp, int length, int negative) { char c, *buffer, message[MSGLEN]; int m; - GFC_INTEGER_LARGEST v, max, max10; + GFC_UINTEGER_LARGEST v, max, max10; + GFC_INTEGER_LARGEST value; buffer = dtp->u.p.saved_string; v = 0; - max = (length == -1) ? MAX_REPEAT : max_value (length, 1); + if (length == -1) + max = MAX_REPEAT; + else + { + max = si_max (length); + if (negative) + max++; + } max10 = max / 10; for (;;) @@ -490,8 +498,10 @@ convert_integer (st_parameter_dt *dtp, int length, int negative) if (length != -1) { if (negative) - v = -v; - set_integer (dtp->u.p.value, v, length); + value = -v; + else + value = v; + set_integer (dtp->u.p.value, value, length); } else { diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c index 32c8b3250f8..c493d5a5f43 100644 --- a/libgfortran/io/read.c +++ b/libgfortran/io/read.c @@ -87,46 +87,34 @@ set_integer (void *dest, GFC_INTEGER_LARGEST value, int length) } -/* max_value()-- Given a length (kind), return the maximum signed or - * unsigned value */ +/* Max signed value of size give by length argument. */ GFC_UINTEGER_LARGEST -max_value (int length, int signed_flag) +si_max (int length) { GFC_UINTEGER_LARGEST value; -#if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10 - int n; -#endif switch (length) - { + { #if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10 case 16: case 10: value = 1; - for (n = 1; n < 4 * length; n++) + for (int n = 1; n < 4 * length; n++) value = (value << 2) + 3; - if (! signed_flag) - value = 2*value+1; - break; + return value; #endif case 8: - value = signed_flag ? 0x7fffffffffffffff : 0xffffffffffffffff; - break; + return GFC_INTEGER_8_HUGE; case 4: - value = signed_flag ? 0x7fffffff : 0xffffffff; - break; + return GFC_INTEGER_4_HUGE; case 2: - value = signed_flag ? 0x7fff : 0xffff; - break; + return GFC_INTEGER_2_HUGE; case 1: - value = signed_flag ? 0x7f : 0xff; - break; + return GFC_INTEGER_1_HUGE; default: internal_error (NULL, "Bad integer kind"); } - - return value; } @@ -634,11 +622,7 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length) return; } - maxv = max_value (length, 1); - maxv_10 = maxv / 10; - negative = 0; - value = 0; switch (*p) { @@ -656,6 +640,11 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length) break; } + maxv = si_max (length); + if (negative) + maxv++; + maxv_10 = maxv / 10; + /* At this point we have a digit-string */ value = 0; @@ -674,20 +663,21 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length) if (c < '0' || c > '9') goto bad; - if (value > maxv_10 && compile_options.range_check == 1) + if (value > maxv_10) goto overflow; c -= '0'; value = 10 * value; - if (value > maxv - c && compile_options.range_check == 1) + if (value > maxv - c) goto overflow; value += c; } - v = value; if (negative) - v = -v; + v = -value; + else + v = value; set_integer (dest, v, length); return; @@ -734,7 +724,8 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length, return; } - maxv = max_value (length, 0); + /* Maximum unsigned value, assuming two's complement. */ + maxv = 2 * si_max (length) + 1; maxv_r = maxv / radix; negative = 0; diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index 051e2e85a1e..7dafd940e62 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -535,7 +535,6 @@ typedef struct size_t record_marker; int max_subrecord_length; int bounds_check; - int range_check; } compile_options_t; diff --git a/libgfortran/runtime/compile_options.c b/libgfortran/runtime/compile_options.c index 0e657f73ba6..2ba1aedf5c5 100644 --- a/libgfortran/runtime/compile_options.c +++ b/libgfortran/runtime/compile_options.c @@ -169,8 +169,10 @@ set_options (int num, int options[]) compile_options.sign_zero = options[5]; if (num >= 7) compile_options.bounds_check = options[6]; - if (num >= 8) - compile_options.range_check = options[7]; + /* options[7] is the -frange-check option, which no longer affects + the library behavior; range checking is now always done when + parsing integers. It's place in the options array is retained due + to ABI compatibility. Remove when bumping the library ABI. */ /* If backtrace is required, we set signal handlers on the POSIX 2001 signals with core action. */ @@ -223,7 +225,6 @@ init_compile_options (void) compile_options.pedantic = 0; compile_options.backtrace = 0; compile_options.sign_zero = 1; - compile_options.range_check = 1; } /* Function called by the front-end to tell us the