Skip to content

Commit

Permalink
[flang][runtime] Don't use endfile record number for EOF detection on… (
Browse files Browse the repository at this point in the history
#74640)

… input

The current EOF detection method (IsAtEOF()) depends on comparing the
current record number with the record number of the endfile record, if
it is known, which it is for units that have been written and then
rewound for input. For formatted input, this is wrong in the case of a
unit written with in-band newline characters. Rather than scan output
data to count newlines, it's best to just organically determine EOF by
detecting a failed or short read(), as we would have done anyway had the
endfile record number not been known. (I considered resetting the
endfile record number at the point of a REWIND, but not all rewinds are
followed by input; it seems wiser to defer the resetting until an actual
READ takes place.)

Fixes llvm-test-suite/Fortran/gfortran/regression/backslash_2.f90
  • Loading branch information
klausler committed Dec 11, 2023
1 parent 0d71df4 commit bf1c89c
Showing 1 changed file with 15 additions and 10 deletions.
25 changes: 15 additions & 10 deletions flang/runtime/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,14 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
RUNTIME_CHECK(handler, direction_ == Direction::Input);
if (!beganReadingRecord_) {
beganReadingRecord_ = true;
// Don't use IsAtEOF() to check for an EOF condition here, just detect
// it from a failed or short read from the file. IsAtEOF() could be
// wrong for formatted input if actual newline characters had been
// written in-band by previous WRITEs before a REWIND. In fact,
// now that we know that the unit is being used for input (again),
// it's best to reset endfileRecordNumber and ensure IsAtEOF() will
// now be true on return only if it gets set by HitEndOnRead().
endfileRecordNumber.reset();
if (access == Access::Direct) {
CheckDirectAccess(handler);
auto need{static_cast<std::size_t>(recordOffsetInFrame_ + *openRecl)};
Expand All @@ -452,17 +460,13 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
}
} else {
recordLength.reset();
if (IsAtEOF()) {
handler.SignalEnd();
} else {
RUNTIME_CHECK(handler, isUnformatted.has_value());
if (*isUnformatted) {
if (access == Access::Sequential) {
BeginSequentialVariableUnformattedInputRecord(handler);
}
} else { // formatted sequential or stream
BeginVariableFormattedInputRecord(handler);
RUNTIME_CHECK(handler, isUnformatted.has_value());
if (*isUnformatted) {
if (access == Access::Sequential) {
BeginSequentialVariableUnformattedInputRecord(handler);
}
} else { // formatted sequential or stream
BeginVariableFormattedInputRecord(handler);
}
}
}
Expand Down Expand Up @@ -727,6 +731,7 @@ void ExternalFileUnit::EndIoStatement() {

void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
IoErrorHandler &handler) {
RUNTIME_CHECK(handler, access == Access::Sequential);
std::int32_t header{0}, footer{0};
std::size_t need{recordOffsetInFrame_ + sizeof header};
std::size_t got{ReadFrame(frameOffsetInFile_, need, handler)};
Expand Down

0 comments on commit bf1c89c

Please sign in to comment.