[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:
parent
8654a0f8bb
commit
e29c9d77f1
|
@ -235,6 +235,7 @@ Cookie BeginUnformattedIO(
|
|||
if (unit.access == Access::Sequential && !unit.isFixedRecordLength) {
|
||||
// Create space for (sub)record header to be completed by
|
||||
// UnformattedIoStatementState<Direction::Output>::EndIoStatement()
|
||||
unit.recordLength.reset(); // in case of prior BACKSPACE
|
||||
io.Emit("\0\0\0\0", 4); // placeholder for record length header
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,16 +132,17 @@ void ExternalFileUnit::OpenUnit(OpenStatus status, std::optional<Action> action,
|
|||
static_cast<std::intmax_t>(*totalBytes));
|
||||
}
|
||||
}
|
||||
endfileRecordNumber.reset();
|
||||
currentRecordNumber = 1;
|
||||
if (totalBytes && recordLength && *recordLength) {
|
||||
endfileRecordNumber = 1 + (*totalBytes / *recordLength);
|
||||
}
|
||||
if (position == Position::Append) {
|
||||
if (totalBytes && recordLength && *recordLength) {
|
||||
endfileRecordNumber = 1 + (*totalBytes / *recordLength);
|
||||
} else {
|
||||
if (!endfileRecordNumber) {
|
||||
// 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;
|
||||
} else {
|
||||
currentRecordNumber = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,7 +375,9 @@ void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
|
|||
void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
|
||||
RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
|
||||
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());
|
||||
if (isFixedRecordLength) {
|
||||
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
|
||||
|
@ -430,16 +433,22 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
|
|||
handler.SignalError(IostatBackspaceNonSequential,
|
||||
"BACKSPACE(UNIT=%d) on non-sequential file", unitNumber());
|
||||
} else {
|
||||
DoImpliedEndfile(handler);
|
||||
--currentRecordNumber;
|
||||
BeginRecord();
|
||||
if (isFixedRecordLength) {
|
||||
BackspaceFixedRecord(handler);
|
||||
} else if (isUnformatted) {
|
||||
BackspaceVariableUnformattedRecord(handler);
|
||||
if (endfileRecordNumber && currentRecordNumber > *endfileRecordNumber) {
|
||||
// BACKSPACE after ENDFILE
|
||||
} 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()) {
|
||||
handler.SignalError(IostatEndfileUnwritable,
|
||||
"ENDFILE(UNIT=%d) on read-only file", unitNumber());
|
||||
} else if (endfileRecordNumber &&
|
||||
currentRecordNumber > *endfileRecordNumber) {
|
||||
// ENDFILE after ENDFILE
|
||||
} else {
|
||||
DoEndfile(handler);
|
||||
++currentRecordNumber;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -469,7 +482,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
|
|||
DoImpliedEndfile(handler);
|
||||
SetPosition(0);
|
||||
currentRecordNumber = 1;
|
||||
// TODO: reset endfileRecordNumber?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue