forked from OSchip/llvm-project
[flang][runtime] Correct emission & reading of unterminated final records
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
This commit is contained in:
parent
9e3b7e8e65
commit
36771bbad1
|
@ -54,6 +54,7 @@ struct ConnectionState : public ConnectionAttributes {
|
|||
void BeginRecord() {
|
||||
positionInRecord = 0;
|
||||
furthestPositionInRecord = 0;
|
||||
unterminatedRecord = false;
|
||||
}
|
||||
|
||||
std::optional<std::int64_t> EffectiveRecordLength() const {
|
||||
|
@ -85,6 +86,10 @@ struct ConnectionState : public ConnectionAttributes {
|
|||
// so that backspacing to the beginning of the repeated item doesn't require
|
||||
// repositioning the external storage medium when that's impossible.
|
||||
bool pinnedFrame{false};
|
||||
|
||||
// Set when the last record of a file is not properly terminated
|
||||
// so that a non-advancing READ will not signal EOR.
|
||||
bool unterminatedRecord{false};
|
||||
};
|
||||
|
||||
// Utility class for capturing and restoring a position in an input stream.
|
||||
|
|
|
@ -327,7 +327,6 @@ void ExternalIoStatementState<DIR>::CompleteOperation() {
|
|||
}
|
||||
unit().leftTabLimit = unit().furthestPositionInRecord;
|
||||
} else {
|
||||
unit().leftTabLimit.reset();
|
||||
unit().AdvanceRecord(*this);
|
||||
}
|
||||
unit().FlushIfTerminal(*this);
|
||||
|
@ -673,7 +672,15 @@ bool IoStatementState::CheckForEndOfRecord() {
|
|||
if (connection.positionInRecord >= *length) {
|
||||
IoErrorHandler &handler{GetIoErrorHandler()};
|
||||
if (mutableModes().nonAdvancing) {
|
||||
handler.SignalEor();
|
||||
if (connection.access == Access::Stream &&
|
||||
connection.unterminatedRecord) {
|
||||
// Reading final unterminated record left by a
|
||||
// non-advancing WRITE on a stream file prior to
|
||||
// positioning or ENDFILE.
|
||||
handler.SignalEnd();
|
||||
} else {
|
||||
handler.SignalEor();
|
||||
}
|
||||
} else if (!connection.modes.pad) {
|
||||
handler.SignalError(IostatRecordReadOverrun);
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes,
|
|||
return true;
|
||||
} else {
|
||||
handler.SignalEnd();
|
||||
if (access == Access::Sequential) {
|
||||
if (IsRecordFile() && access != Access::Direct) {
|
||||
endfileRecordNumber = currentRecordNumber;
|
||||
}
|
||||
return false;
|
||||
|
@ -385,7 +385,7 @@ const char *ExternalFileUnit::FrameNextInput(
|
|||
return Frame() + at;
|
||||
}
|
||||
handler.SignalEnd();
|
||||
if (access == Access::Sequential) {
|
||||
if (IsRecordFile() && access != Access::Direct) {
|
||||
endfileRecordNumber = currentRecordNumber;
|
||||
}
|
||||
}
|
||||
|
@ -544,6 +544,7 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
|
|||
#endif
|
||||
ok = ok && Emit(lineEnding, lineEndingBytes, 1, handler);
|
||||
}
|
||||
leftTabLimit.reset();
|
||||
if (IsAfterEndfile()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -620,7 +621,7 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) {
|
|||
// ENDFILE after ENDFILE
|
||||
} else {
|
||||
DoEndfile(handler);
|
||||
if (access == Access::Sequential) {
|
||||
if (IsRecordFile() && access != Access::Direct) {
|
||||
// Explicit ENDFILE leaves position *after* the endfile record
|
||||
RUNTIME_CHECK(handler, endfileRecordNumber.has_value());
|
||||
currentRecordNumber = *endfileRecordNumber + 1;
|
||||
|
@ -716,6 +717,7 @@ void ExternalFileUnit::BeginVariableFormattedInputRecord(
|
|||
if (length > 0) {
|
||||
// final record w/o \n
|
||||
recordLength = length;
|
||||
unterminatedRecord = true;
|
||||
} else {
|
||||
handler.SignalEnd();
|
||||
}
|
||||
|
@ -839,11 +841,17 @@ void ExternalFileUnit::DoImpliedEndfile(IoErrorHandler &handler) {
|
|||
}
|
||||
|
||||
void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) {
|
||||
if (IsRecordFile()) {
|
||||
if (IsRecordFile() && access != Access::Direct) {
|
||||
if (furthestPositionInRecord > 0) {
|
||||
// Last write was non-advancing, so AdvanceRecord() was not called.
|
||||
leftTabLimit.reset();
|
||||
++currentRecordNumber;
|
||||
}
|
||||
endfileRecordNumber = currentRecordNumber;
|
||||
}
|
||||
FlushOutput(handler);
|
||||
Truncate(frameOffsetInFile_ + recordOffsetInFrame_, handler);
|
||||
Truncate(frameOffsetInFile_ + recordOffsetInFrame_ + furthestPositionInRecord,
|
||||
handler);
|
||||
BeginRecord();
|
||||
impliedEndfile_ = false;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue