Skip to content

Commit bf1c89c

Browse files
authored
[flang][runtime] Don't use endfile record number for EOF detection on… (#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
1 parent 0d71df4 commit bf1c89c

File tree

1 file changed

+15
-10
lines changed

1 file changed

+15
-10
lines changed

flang/runtime/unit.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,14 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
440440
RUNTIME_CHECK(handler, direction_ == Direction::Input);
441441
if (!beganReadingRecord_) {
442442
beganReadingRecord_ = true;
443+
// Don't use IsAtEOF() to check for an EOF condition here, just detect
444+
// it from a failed or short read from the file. IsAtEOF() could be
445+
// wrong for formatted input if actual newline characters had been
446+
// written in-band by previous WRITEs before a REWIND. In fact,
447+
// now that we know that the unit is being used for input (again),
448+
// it's best to reset endfileRecordNumber and ensure IsAtEOF() will
449+
// now be true on return only if it gets set by HitEndOnRead().
450+
endfileRecordNumber.reset();
443451
if (access == Access::Direct) {
444452
CheckDirectAccess(handler);
445453
auto need{static_cast<std::size_t>(recordOffsetInFrame_ + *openRecl)};
@@ -452,17 +460,13 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
452460
}
453461
} else {
454462
recordLength.reset();
455-
if (IsAtEOF()) {
456-
handler.SignalEnd();
457-
} else {
458-
RUNTIME_CHECK(handler, isUnformatted.has_value());
459-
if (*isUnformatted) {
460-
if (access == Access::Sequential) {
461-
BeginSequentialVariableUnformattedInputRecord(handler);
462-
}
463-
} else { // formatted sequential or stream
464-
BeginVariableFormattedInputRecord(handler);
463+
RUNTIME_CHECK(handler, isUnformatted.has_value());
464+
if (*isUnformatted) {
465+
if (access == Access::Sequential) {
466+
BeginSequentialVariableUnformattedInputRecord(handler);
465467
}
468+
} else { // formatted sequential or stream
469+
BeginVariableFormattedInputRecord(handler);
466470
}
467471
}
468472
}
@@ -727,6 +731,7 @@ void ExternalFileUnit::EndIoStatement() {
727731

728732
void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
729733
IoErrorHandler &handler) {
734+
RUNTIME_CHECK(handler, access == Access::Sequential);
730735
std::int32_t header{0}, footer{0};
731736
std::size_t need{recordOffsetInFrame_ + sizeof header};
732737
std::size_t got{ReadFrame(frameOffsetInFile_, need, handler)};

0 commit comments

Comments
 (0)