…hecks
An OPEN statement on an existing unit can imply a CLOSE of that unit;
for example, OPEN(5, FILE="mydata", FORM="formatted") should implicitly
close the standard input that had been preconnected to unit 5. When this
happens, later checks in OPEN statement completion that apply only to
existing units should be disabled.
For nonexistent or inaccessible files, we're returning NO, which is
indeed true, but we should return UNKNOWN instead.
Differential Revision: https://reviews.llvm.org/D158653
It is an error to open a new unit with OPEN(NEWUNIT=) and have
neither a file name nor a scratch status. Catch it, and report a
new error code.
Differential Revision: https://reviews.llvm.org/D155967
When a formatted I/O READ statement processes a DT edit descriptor to call a
user-defined I/O subroutine to read a derived type data item, all of the
characters that that subroutine reads via child I/O count as charecters
read by an edit descriptor and should accumulate in the result returned
by a SIZE= item in the original READ statement's control list.
Differential Revision: https://reviews.llvm.org/D144234
My earlier misreading of the Fortran standards had convinced me that child I/O
-- meaning the use of user-defined subroutines via generic interfaces to implement
data transfer statements -- was not allowed to advance the current record in the
ultimate unit of the original (non-child parent) data transfer statement.
This turns out to be wrong, so forward AdvanceRecord() from ChildFormattedIoStatement<>
to its parent I/O statement rather than implementing it as a no-op.
Differential Revision: https://reviews.llvm.org/D144205
During child I/O -- a call to a user-defined subroutine with a generic interface
to handle read and write operations on a specific derived type -- ensure that
any INQUIRE statement probing mutable modes like BLANK= will observe changes
that have been made to those modes via control edit descriptors like BN
while processing the original I/O statement's format.
Differential Revision: https://reviews.llvm.org/D144046
Add the remaining pieces to support IO for noncontigous formats.
This is done by passing an array descriptor to IO calls. Scalar
formats continue to pass string and length arguments. IO calls
with formats are modified to place the new format descriptor
argument directly after the original string and length arguments.
A character array can be used as a format in an I/O data transfer
statement, with the interpretation that its elements are concatenated
in element order to constitute the format.
Support in the runtime with an extra optional descriptor argument
to six I/O API calls; support in semantics by removing an earlier
check for a simply contiguous array presented as a format.
Some work needs to be done in lowering to pass a character array
descriptor to the I/O runtime API when present
Differential Revision: https://reviews.llvm.org/D132167
Remove a lambda capture of "[this]" in two cases where it
is no longer required. Will be pushed without waiting for
review if CI is successful in order to resolve a sad build bot.
Differential Revision: https://reviews.llvm.org/D131506
Allow internal I/O to support non-default kinds of CHARACTER.
The I/O runtime design anticipated this standard feature, but
this patch is somewhat larger than I thought it would be because
many code sites had to have assumptions about units (characters
vs. bytes) brought into harmony, and some encoding utilities
had to be pulled out of IoStatementState and templatized into
their own new header file so that they are available to formatted
output code without having to "thread" an IoStatementState reference
through many call chains.
Differential Revision: https://reviews.llvm.org/D131107
Most of the infrastructure for DECIMAL='COMMA' mode was in place
in the I/O runtime support library, but I dropped the ball for
list-directed character input, which has its own detection of
input separators. Finish the job.
Differential Revision: https://reviews.llvm.org/D129679
The check for the PAD= setting should examine the mutable modes
of the current I/O statement, not the persistent modes of the
I/O unit.
Differential Revision: https://reviews.llvm.org/D128389
When an unconnected unit number is used in a BACKSPACE statement
with ERR=, IOSTAT=, &/or IOMSG= control specifiers, don't crash,
but let the program deal with the error.
Differential Revision: https://reviews.llvm.org/D127782
After a recoverable error condition in a READ statement with ADVANCE='NO',
skip the remainder of the current record.
Differential Revision: https://reviews.llvm.org/D127433
The little state machine in GetNextDataEdit() wasn't transitioning
properly from reading the imaginary part of the number back to the
real part for the next iteration of a repeated value.
Differential Revision: https://reviews.llvm.org/D127422
Track pending "asynchronous" I/O operation IDs so that WAIT statements can
report errors about bad ID numbers.
Lowering will need to extended to call GetAsynchronousId() for a READ or
WRITE statement with ID=n.
Differential Revision: https://reviews.llvm.org/D127421
When nonadvancing output uses T/TL control edit descriptors to reposition
the record, don't reset the position to the furthest point written at
the end of the write.
Differential Revision: https://reviews.llvm.org/D127420
When an external I/O statement is in a recoverable error
state before any data transfers take place (for example,
an unformatted transfer with ERR=/IOSTAT=/IOMSG= attempted on
a formatted unit), ensure that the unit's mutex is still
released at the end of the statement.
Differential Revision: https://reviews.llvm.org/D127032
Whether a unit number in an inquire-by-unit statement is valid or not,
it should be the value to which the NUMBER= variable is set, not -1.
-1 should be returned to NUMBER= only for an inquire-by-file statement
when the FILE= is not connected to any unit.
Differential Revision: https://reviews.llvm.org/D126145
A BACKSPACE statement on a unit after a READ or WRITE with ADVANCE="NO"
must reset the position to the beginning of the record, not to the
beginning of the previous one.
Differential Revision: https://reviews.llvm.org/D125057
When the last operation on a foramtted sequential or stream file (prior
to an implied or explicit ENDFILE) is a non-advancing WRITE, ensure
that any partial record data is emitted to the file without a line
terminator. Further, when that last record is read with a non-advancing
READ, ensure that it won't raise an end-of-record condition after its
data, but instead will signal an end-of-file.
Differential Revision: https://reviews.llvm.org/D124546
When PAD='NO' and ADVANCE='YES', we currently signal an input
error when a formatted read tries to go past the end of a record
only when a fixed RECL= is in effect. Other compilers will signal
an error without RECL= too, and that seems like a precedent we
should follow.
Differential Revision: https://reviews.llvm.org/D124301
Adds flang/include/flang/Common/log2-visit.h, which defines
a Fortran::common::visit() template function that is a drop-in
replacement for std::visit(). Modifies most use sites in
the front-end and runtime to use common::visit().
The C++ standard mandates that std::visit() have O(1) execution
time, which forces implementations to build dispatch tables.
This new common::visit() is O(log2 N) in the number of alternatives
in a variant<>, but that N tends to be small and so this change
produces a fairly significant improvement in compiler build
memory requirements, a 5-10% improvement in compiler build time,
and a small improvement in compiler execution time.
Building with -DFLANG_USE_STD_VISIT causes common::visit()
to be an alias for std::visit().
Calls to common::visit() with multiple variant arguments
are referred to std::visit(), pending further work.
This change is enabled only for GCC builds with GCC >= 9;
an earlier attempt (D122441) ran into bugs in some versions of
clang and was reverted rather than simply disabled; and it is
not well tested with MSVC. In non-GCC and older GCC builds,
common::visit() is simply an alias for std::visit().
When formatted non-advancing output ends in a control edit descriptor
like nX or Tn or TRn that effectively extends the record, fill any
gap with explicit blanks at the completion of the WRITE.
Differential Revision: https://reviews.llvm.org/D123716
A recent change to implement UTF-8 encoding should have
made the encoding conditional only for CHARACTER(KIND=1)
to enable UTF-8 output vs. Latin-1 or whatever. UTF-8 output
of wider CHARACTER kinds should not be conditional (until we choose
to support UCS-16, maybe). So wider CHARACTER kinds are being
emitted with extra zero bytes; this patch fixes them.
Differential Revision: https://reviews.llvm.org/D123711
Correct the implementation of non-advancing I/O after some testing
to ensure that T tab edit descriptors are not allowed to back up
into positions of a record prior to where it stood at the beginning
of the I/O statement.
Differential Revision: https://reviews.llvm.org/D123709
STATUS='NEW' and 'REPLACE' require FILE= to be present.
STATUS='SCRATCH' may not appear with FILE=.
These errors are caught at compilation time when constant character
strings are used in an OPEN statement, but the runtime needs
to enforce them as well to catch errors in OPEN statements
with character variables and expressions.
Differential Revision: https://reviews.llvm.org/D122509
Adds flang/include/flang/Common/visit.h, which defines
a Fortran::common::visit() template function that is a drop-in
replacement for std::visit(). Modifies most use sites in
the front-end and runtime to use common::visit().
The C++ standard mandates that std::visit() have O(1) execution
time, which forces implementations to build dispatch tables.
This new common::visit() is O(log2 N) in the number of alternatives
in a variant<>, but that N tends to be small and so this change
produces a fairly significant improvement in compiler build
memory requirements, a 5-10% improvement in compiler build time,
and a small improvement in compiler execution time.
Building with -DFLANG_USE_STD_VISIT causes common::visit()
to be an alias for std::visit().
Calls to common::visit() with multiple variant arguments
are referred to std::visit(), pending further work.
Differential Revision: https://reviews.llvm.org/D122441
Implements UTF-8 encoding and decoding for external units
with OPEN(ENCODING='UTF-8'). This encoding applies to default
CHARACTER values that are not 7-bit ASCII as well as to
the wide CHARACTER kinds 2 and 4. Basic testing is in place
via direct calls to the runtime I/O APIs, but serious checkout
awaits lowering support of the wide CHARACTER kinds.
Differential Revision: https://reviews.llvm.org/D122038
Some refactoring and related fixes for more accurate
user program error recovery in the I/O runtime, especially
for error recovery with IOMSG= character values.
1) Move any work in an EndIoStatement() implementation
that may raise an error into a new CompleteOperation()
member function. This allows error handling APIs like
GetIoMsg() to complete a pending I/O statement and harvest
any errors that may result.
2) Move the pending error code from ErroneousIoStatementState
to a new pendingError_ data member in IoErrorHandler.
This allows IoErrorHandler::InError() to return a correct
result when there is a pending error that will be recovered
from so that I/O list data transfers don't crash in the meantime.
3) Don't create and leak a unit for a failed OPEN(NEWUNIT=n)
with error recovery, and don't modify 'n'. (Depends on
changes to API call ordering in lowering, in a separate patch;
code was added to ensure that OPEN statement control list
specifiers, e.g. SetFile(), must be passed before GetNewUnit().)
4) Fix the code that calls a form of strerror to fill an
IOMSG= variable so that it actually works for Fortran's
character type: blank fill with no null or newline termination.
Differential Revision: https://reviews.llvm.org/D122036
Where possible, I added additional information to the messages to help
programmers figure out what went wrong. I also removed all uses of the word
"bad" from the messages since (to me) that implies a moral judgement rather
than a programming error. I replaced it with either "invalid" or "unsupported"
where appropriate.
Differential Revision: https://reviews.llvm.org/D121493
Rather than reading default character variables in formatted
input one byte at a time via NextInField(), skip and read
them via blocks of available buffer data. This eliminates
a bottleneck that affected reads of large character values.
(It also exposed a problem with sequential reads with RECL=
set on the OPEN statement, so that's fixed too.)
Differential Revision: https://reviews.llvm.org/D121144
The runtime crashes on several fundamental I/O data transfer statement
control list errors, like list I/O on a direct-access unit, or
input from a write-only unit, &c. These errors should not be fatal
when ERR= or IOSTAT= are present.
This patch creates a new ErroneousIoStatementState class and
uses it for the state of an I/O statement that is doomed to fail
from these errors. If there is no ERR= label or IOSTAT= variable,
the error will be raised at the end of the statement. Data transfer
operations along the way will be no-op failures.
Differential Revision: https://reviews.llvm.org/D120745
Corrects the runtime implementation of I/O on files with
the access mode ACCESS='STREAM'. This is a collection
of edge-case tweaks to ensure that the distinctions between
stream and direct/sequential files, unformatted or formatted,
are respected where appropriate.
Moves NextInField() from io-stmt.h to io-stmt.cpp --
it was getting too big to keep in a header.
This patch exposed a problem with the I/O runtime
on Windows and it was reverted. This version also
fixes that problem; files are now opened on Windows
in binary mode to prevent inadvertent insertions of
carriage returns before line feeds, and those line
endings (CR+LF) are now explicitly generated.
Differential Revision: https://reviews.llvm.org/D119015
Corrects the runtime implementation of I/O on files with
the access mode ACCESS='STREAM'. This is a collection
of edge-case tweaks to ensure that the distinctions between
stream and direct/sequential files, unformatted or formatted,
are respected where appropriate.
Moves NextInField() from io-stmt.h to io-stmt.cpp --
it was getting too big to keep in a header.
Differential Revision: https://reviews.llvm.org/D118834
RECL= is required for direct access I/O, but is permitted
as well for sequential I/O, where it is defined by the
standard to specify a maximum record (line) length.
The standard does not say what should happen when an
sequential formatted input record appears whose length is
unequal to RECL= when it is specified.
Precedents from other compilers are unclear: one raises an error,
some honor RECL= as an effective truncation, and a few ignore the
situation. On output, all other compilers tested raised an
error when an attempt is made to emit a record longer than RECL=.
This patch treats RECL= as effective truncation on input and
as a hard limit with error on output, and also ensures that
RECL= can be set *longer* than the actual input record lengths.
Differential Revision: https://reviews.llvm.org/D115102
INQUIRE(POSITION=)'s results need to reflect the POSITION=
specifier used for the OPEN statement until the unit has been
repositioned. Preserve the POSITION= from OPEN and used it
for INQUIRE(POSITION=) until is becomes obsolete.
INQUIRE(PAD=) is implemented here in the case of an unconnected unit
with Fortran 2018 semantics; i.e., "UNDEFINED", rather than Fortran 90's
"YES"/"NO" (see 4.3.6 para 2). Apparent failures with F'90-only tests
will persist with INQUIRE(PAD=); these discrepancies don't seem to warrant
an option or environment variable.
To make the implementation of INQUIRE more closely match the language
in the standard, rename IsOpen() to IsConnected(), and use it explicitly
for the various INQUIRE specifiers.
Differential Revision: https://reviews.llvm.org/D114755
The predefined units were not being initialized with FORM='FORMATTED',
so INQUIRE(PAD=) was failing if no I/O had already been done.
INQUIRE(POSITION=) was returning 'REWIND' on stdin/stdout (which
is somewhat defensible from the definition, and is what Intel Fortran
does), but most implementations return 'ASIS'. Change the runtime
to return 'REWIND' only for positionable external files, but 'ASIS'
for terminals, sockets, &c.
Differential Revision: https://reviews.llvm.org/D114028
The inquire by output list form of the INQUIRE statement calculates the
number of file storage units that would be required to store the data
of an output list in an unformatted file. Currently, the result is
incorrectly multiplied by the number of bytes for a data type. A query
for "INTEGER(KIND=4) A(10)" should be 40, not 160.
Update formatting.
1. To avoid overwriting the part of the record read in the non advancing read,
the furtherPositionInRecord field must be set to the max of the
furtherPositionInRecord and the positionInRecord at the beginning of the
IO write.
2. To allow any further read to succeed after the write, the unit
beganReadingRecord_ must be set to false when resetting the recordLength
during the write, otherwise, recordLength will not be computed in further
read and an assert is hit (at unit.cpp(398)).
The added unit test exercises both of these scenarios.
Differential Revision: https://reviews.llvm.org/D113740