aboutsummaryrefslogtreecommitdiff
path: root/libgfortran/io/unit.c
diff options
context:
space:
mode:
authorJanne Blomqvist <jb@gcc.gnu.org>2017-11-28 21:28:50 +0200
committerJanne Blomqvist <jb@gcc.gnu.org>2017-11-28 21:28:50 +0200
commit67c24a8bd6141021da49e005c0111bd42bfc7d08 (patch)
tree4255e7df80923463cf7ce62bf84f31f5f890ab13 /libgfortran/io/unit.c
parent6df8934f6ad73b97181fc0a997b3eb8cd799b6a0 (diff)
downloadgcc-67c24a8bd6141021da49e005c0111bd42bfc7d08.zip
gcc-67c24a8bd6141021da49e005c0111bd42bfc7d08.tar.gz
gcc-67c24a8bd6141021da49e005c0111bd42bfc7d08.tar.bz2
PR 53796 Improve INQUIRE(RECL=...) handling
The current F2018 draft (N2137) specifies behavior of the RECL= specifier in the INQUIRE statement, where it previously was left as undefined. Namely: - If the unit is not connected, RECL= should be given the value -1. - If the unit is connected with stream access, RECL= should be given the value -2. Further, as PR 53796 describes, the handling of RECL= is poor in other ways as well. When the recl is set to the maximum possible (GFC_INTEGER_8_HUGE / LLONG_MAX), which it does by default except for preconnected units, and when INQUIRE(RECL=) is used with a 4 byte integer, the value is truncated and the 4 byte value is thus -1. Fixing this to generate an error is a lot of work, as currently the truncation is done by the frontend, the library sees only an 8 byte value with no indication that the frontend is going to copy it to a 4 byte one. Instead, this patch does a bit twiddling trick such that the truncated 4 byte value is GFC_INTEGER_4_HUGE while still being 0.99999999 * GFC_INTEGER_8_HUGE which is large enough for all practical purposes. Finally, the patch removes GFORTRAN_DEFAULT_RECL which was used only for preconnected units, and instead uses the same approach as describe above. Regtested on x86_64-pc-linux-gnu, Ok for trunk. gcc/fortran/ChangeLog: 2017-11-28 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/53796 * gfortran.texi: Remove mentions of GFORTRAN_DEFAULT_RECL. libgfortran/ChangeLog: 2017-11-28 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/53796 * io/inquire.c (inquire_via_unit): Set recl to -1 for unconnected units. * io/io.h (default_recl): New variable. * io/open.c (new_unit): Set recl to default_recl for sequential, -2 for stream access. * io/transfer.c (read_block_form): Test against default_recl instead of DEFAULT_RECL. (write_block): Likewise. * io/unit.c (init_units): Calculate max_offset, default_recl. * libgfortran.h (DEFAULT_RECL): Remove. * runtime/environ.c: Remove GFORTRAN_DEFAULT_RECL. gcc/testsuite/ChangeLog: 2017-11-28 Janne Blomqvist <jb@gcc.gnu.org> PR fortran/53796 * gfortran.dg/inquire_recl_f2018.f90: New test. From-SVN: r255215
Diffstat (limited to 'libgfortran/io/unit.c')
-rw-r--r--libgfortran/io/unit.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/libgfortran/io/unit.c b/libgfortran/io/unit.c
index e62f9b8..fbb3304 100644
--- a/libgfortran/io/unit.c
+++ b/libgfortran/io/unit.c
@@ -95,7 +95,10 @@ static int newunit_lwi;
#define CACHE_SIZE 3
static gfc_unit *unit_cache[CACHE_SIZE];
+
gfc_offset max_offset;
+gfc_offset default_recl;
+
gfc_unit *unit_root;
#ifdef __GTHREAD_MUTEX_INIT
__gthread_mutex_t unit_lock = __GTHREAD_MUTEX_INIT;
@@ -575,7 +578,6 @@ void
init_units (void)
{
gfc_unit *u;
- unsigned int i;
#ifdef HAVE_NEWLOCALE
c_locale = newlocale (0, "C", 0);
@@ -589,6 +591,22 @@ init_units (void)
__GTHREAD_MUTEX_INIT_FUNCTION (&unit_lock);
#endif
+ if (sizeof (max_offset) == 8)
+ {
+ max_offset = GFC_INTEGER_8_HUGE;
+ /* Why this weird value? Because if the recl specifier in the
+ inquire statement is a 4 byte value, u->recl is truncated,
+ and this trick ensures it becomes HUGE(0) rather than -1.
+ The full 8 byte value of default_recl is still 0.99999999 *
+ max_offset which is large enough for all practical
+ purposes. */
+ default_recl = max_offset & ~(1LL<<31);
+ }
+ else if (sizeof (max_offset) == 4)
+ max_offset = default_recl = GFC_INTEGER_4_HUGE;
+ else
+ internal_error (NULL, "sizeof (max_offset) must be 4 or 8");
+
if (options.stdin_unit >= 0)
{ /* STDIN */
u = insert_unit (options.stdin_unit);
@@ -611,7 +629,7 @@ init_units (void)
u->flags.share = SHARE_UNSPECIFIED;
u->flags.cc = CC_LIST;
- u->recl = options.default_recl;
+ u->recl = default_recl;
u->endfile = NO_ENDFILE;
u->filename = strdup (stdin_name);
@@ -642,7 +660,7 @@ init_units (void)
u->flags.share = SHARE_UNSPECIFIED;
u->flags.cc = CC_LIST;
- u->recl = options.default_recl;
+ u->recl = default_recl;
u->endfile = AT_ENDFILE;
u->filename = strdup (stdout_name);
@@ -672,7 +690,7 @@ init_units (void)
u->flags.share = SHARE_UNSPECIFIED;
u->flags.cc = CC_LIST;
- u->recl = options.default_recl;
+ u->recl = default_recl;
u->endfile = AT_ENDFILE;
u->filename = strdup (stderr_name);
@@ -682,13 +700,6 @@ init_units (void)
__gthread_mutex_unlock (&u->lock);
}
-
- /* Calculate the maximum file offset in a portable manner.
- max will be the largest signed number for the type gfc_offset.
- set a 1 in the LSB and keep a running sum, stopping at MSB-1 bit. */
- max_offset = 0;
- for (i = 0; i < sizeof (max_offset) * 8 - 1; i++)
- max_offset = max_offset + ((gfc_offset) 1 << i);
}