[flang] Fix WRITE after BACKSPACE

A WRITE to an unformatted sequential variable-length unit after
a BACKSPACE needs to forget its previous knowledge of the length
of the record that's about to be overwritten, and a BACKSPACE
after an ENDFILE or at the start of the file needs to be a no-op.

Differential revision: https://reviews.llvm.org/D88675
This commit is contained in:
peter klausler 2020-10-01 09:50:48 -07:00
parent 8654a0f8bb
commit e29c9d77f1
2 changed files with 29 additions and 16 deletions

View File

@ -235,6 +235,7 @@ Cookie BeginUnformattedIO(
if (unit.access == Access::Sequential && !unit.isFixedRecordLength) { if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
// Create space for (sub)record header to be completed by // Create space for (sub)record header to be completed by
// UnformattedIoStatementState<Direction::Output>::EndIoStatement() // UnformattedIoStatementState<Direction::Output>::EndIoStatement()
unit.recordLength.reset(); // in case of prior BACKSPACE
io.Emit("\0\0\0\0", 4); // placeholder for record length header io.Emit("\0\0\0\0", 4); // placeholder for record length header
} }
} }

View File

@ -132,16 +132,17 @@ void ExternalFileUnit::OpenUnit(OpenStatus status, std::optional<Action> action,
static_cast<std::intmax_t>(*totalBytes)); static_cast<std::intmax_t>(*totalBytes));
} }
} }
endfileRecordNumber.reset();
currentRecordNumber = 1;
if (totalBytes && recordLength && *recordLength) {
endfileRecordNumber = 1 + (*totalBytes / *recordLength);
}
if (position == Position::Append) { if (position == Position::Append) {
if (totalBytes && recordLength && *recordLength) { if (!endfileRecordNumber) {
endfileRecordNumber = 1 + (*totalBytes / *recordLength);
} else {
// Fake it so that we can backspace relative from the end // Fake it so that we can backspace relative from the end
endfileRecordNumber = std::numeric_limits<std::int64_t>::max() - 1; endfileRecordNumber = std::numeric_limits<std::int64_t>::max() - 2;
} }
currentRecordNumber = *endfileRecordNumber; currentRecordNumber = *endfileRecordNumber;
} else {
currentRecordNumber = 1;
} }
} }
@ -374,7 +375,9 @@ void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) { void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_); RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
beganReadingRecord_ = false; beganReadingRecord_ = false;
if (access == Access::Sequential) { if (handler.GetIoStat() != IostatOk) {
// avoid bogus crashes in END/ERR circumstances
} else if (access == Access::Sequential) {
RUNTIME_CHECK(handler, recordLength.has_value()); RUNTIME_CHECK(handler, recordLength.has_value());
if (isFixedRecordLength) { if (isFixedRecordLength) {
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength; frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
@ -430,16 +433,22 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
handler.SignalError(IostatBackspaceNonSequential, handler.SignalError(IostatBackspaceNonSequential,
"BACKSPACE(UNIT=%d) on non-sequential file", unitNumber()); "BACKSPACE(UNIT=%d) on non-sequential file", unitNumber());
} else { } else {
DoImpliedEndfile(handler); if (endfileRecordNumber && currentRecordNumber > *endfileRecordNumber) {
--currentRecordNumber; // BACKSPACE after ENDFILE
BeginRecord();
if (isFixedRecordLength) {
BackspaceFixedRecord(handler);
} else if (isUnformatted) {
BackspaceVariableUnformattedRecord(handler);
} else { } else {
BackspaceVariableFormattedRecord(handler); DoImpliedEndfile(handler);
if (frameOffsetInFile_ + recordOffsetInFrame_ > 0) {
--currentRecordNumber;
if (isFixedRecordLength) {
BackspaceFixedRecord(handler);
} else if (isUnformatted) {
BackspaceVariableUnformattedRecord(handler);
} else {
BackspaceVariableFormattedRecord(handler);
}
}
} }
BeginRecord();
} }
} }
@ -456,8 +465,12 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) {
} else if (!mayWrite()) { } else if (!mayWrite()) {
handler.SignalError(IostatEndfileUnwritable, handler.SignalError(IostatEndfileUnwritable,
"ENDFILE(UNIT=%d) on read-only file", unitNumber()); "ENDFILE(UNIT=%d) on read-only file", unitNumber());
} else if (endfileRecordNumber &&
currentRecordNumber > *endfileRecordNumber) {
// ENDFILE after ENDFILE
} else { } else {
DoEndfile(handler); DoEndfile(handler);
++currentRecordNumber;
} }
} }
@ -469,7 +482,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
DoImpliedEndfile(handler); DoImpliedEndfile(handler);
SetPosition(0); SetPosition(0);
currentRecordNumber = 1; currentRecordNumber = 1;
// TODO: reset endfileRecordNumber?
} }
} }