[flang] Allow record advancement in external formatted sequential READ

The '/' control edit descriptor causes a runtime crash for an
external formatted sequential READ because the AdvanceRecord()
member function for external units implemented only the tasks
to finish reading the current record.  Split those out into
a new FinishReadingRecord() member function, call that instead
from EndIoStatement(), and change AdvanceRecord() to both
finish reading the current record and to begin reading the next
one.

Differential revision: https://reviews.llvm.org/D88607
This commit is contained in:
peter klausler 2020-09-30 12:53:00 -07:00
parent d689570d7d
commit e24f0ac7a3
4 changed files with 60 additions and 34 deletions

View File

@ -236,11 +236,13 @@ int NoUnitIoStatementState::EndIoStatement() {
template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
if constexpr (DIR == Direction::Input) {
BeginReadingRecord(); // in case of READ with no data items
}
if (!unit().nonAdvancing && GetIoStat() != IostatEnd) {
unit().AdvanceRecord(*this);
}
if constexpr (DIR == Direction::Output) {
if (!unit().nonAdvancing) {
FinishReadingRecord();
}
} else {
if (!unit().nonAdvancing) {
unit().AdvanceRecord(*this);
}
unit().FlushIfTerminal(*this);
}
return ExternalIoStatementBase::EndIoStatement();
@ -315,10 +317,20 @@ void ExternalIoStatementState<DIR>::HandleRelativePosition(std::int64_t n) {
template <Direction DIR>
void ExternalIoStatementState<DIR>::BeginReadingRecord() {
if constexpr (DIR == Direction::Input) {
if (!beganReading_) {
beganReading_ = true;
unit().BeginReadingRecord(*this);
}
unit().BeginReadingRecord(*this);
} else {
Crash("ExternalIoStatementState<Direction::Output>::BeginReadingRecord() "
"called");
}
}
template <Direction DIR>
void ExternalIoStatementState<DIR>::FinishReadingRecord() {
if constexpr (DIR == Direction::Input) {
unit().FinishReadingRecord(*this);
} else {
Crash("ExternalIoStatementState<Direction::Output>::FinishReadingRecord() "
"called");
}
}

View File

@ -65,6 +65,7 @@ public:
ExternalFileUnit *GetExternalFileUnit() const; // null if internal unit
MutableModes &mutableModes();
void BeginReadingRecord();
void FinishReadingRecord();
bool Inquire(InquiryKeywordHash, char *, std::size_t);
bool Inquire(InquiryKeywordHash, bool &);
bool Inquire(InquiryKeywordHash, std::int64_t, bool &); // PENDING=
@ -123,7 +124,7 @@ struct IoStatementBase : public DefaultFormatControlCallbacks {
std::optional<DataEdit> GetNextDataEdit(IoStatementState &, int = 1);
ExternalFileUnit *GetExternalFileUnit() const { return nullptr; }
void BeginReadingRecord() {}
void FinishReadingRecord() {}
bool Inquire(InquiryKeywordHash, char *, std::size_t);
bool Inquire(InquiryKeywordHash, bool &);
bool Inquire(InquiryKeywordHash, std::int64_t, bool &);
@ -269,9 +270,7 @@ public:
void HandleRelativePosition(std::int64_t);
void HandleAbsolutePosition(std::int64_t);
void BeginReadingRecord();
private:
bool beganReading_{false};
void FinishReadingRecord();
};
template <Direction DIR, typename CHAR>

View File

@ -349,6 +349,10 @@ void ExternalFileUnit::SetLeftTabLimit() {
void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
RUNTIME_CHECK(handler, direction_ == Direction::Input);
if (beganReadingRecord_) {
return;
}
beganReadingRecord_ = true;
if (access == Access::Sequential) {
if (endfileRecordNumber && currentRecordNumber >= *endfileRecordNumber) {
handler.SignalEnd();
@ -367,28 +371,37 @@ void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
}
}
void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
beganReadingRecord_ = false;
if (access == Access::Sequential) {
RUNTIME_CHECK(handler, recordLength.has_value());
if (isFixedRecordLength) {
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
recordOffsetInFrame_ = 0;
} else if (isUnformatted) {
// Retain footer in frame for more efficient BACKSPACE
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
recordOffsetInFrame_ = sizeof(std::uint32_t);
recordLength.reset();
} else { // formatted
if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') {
++recordOffsetInFrame_;
}
recordOffsetInFrame_ += *recordLength + 1;
RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n');
recordLength.reset();
}
}
++currentRecordNumber;
BeginRecord();
}
bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
bool ok{true};
if (direction_ == Direction::Input) {
if (access == Access::Sequential) {
RUNTIME_CHECK(handler, recordLength.has_value());
if (isFixedRecordLength) {
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
recordOffsetInFrame_ = 0;
} else if (isUnformatted) {
// Retain footer in frame for more efficient BACKSPACE
frameOffsetInFile_ += recordOffsetInFrame_ + *recordLength;
recordOffsetInFrame_ = sizeof(std::uint32_t);
recordLength.reset();
} else { // formatted
if (Frame()[recordOffsetInFrame_ + *recordLength] == '\r') {
++recordOffsetInFrame_;
}
recordOffsetInFrame_ += *recordLength + 1;
RUNTIME_CHECK(handler, Frame()[recordOffsetInFrame_ - 1] == '\n');
recordLength.reset();
}
}
FinishReadingRecord(handler);
BeginReadingRecord(handler);
} else { // Direction::Output
if (!isUnformatted) {
if (isFixedRecordLength && recordLength) {
@ -406,9 +419,9 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
recordOffsetInFrame_ + recordLength.value_or(furthestPositionInRecord);
recordOffsetInFrame_ = 0;
impliedEndfile_ = true;
++currentRecordNumber;
BeginRecord();
}
++currentRecordNumber;
BeginRecord();
return ok;
}

View File

@ -78,6 +78,7 @@ public:
std::optional<char32_t> GetCurrentChar(IoErrorHandler &);
void SetLeftTabLimit();
void BeginReadingRecord(IoErrorHandler &);
void FinishReadingRecord(IoErrorHandler &);
bool AdvanceRecord(IoErrorHandler &);
void BackspaceRecord(IoErrorHandler &);
void FlushIfTerminal(IoErrorHandler &);
@ -105,6 +106,7 @@ private:
int unitNumber_{-1};
Direction direction_{Direction::Output};
bool impliedEndfile_{false}; // seq. output has taken place
bool beganReadingRecord_{false};
Lock lock_;