[flang] Handle END= situations better in runtime input

Debug the input path for READ statements with END= labels;
don't emit errors when the program can handle them.
BeginReadingRecord() member functions have been made
"bool" for more convenient handling of error cases,
and some code in IoErrorHandler has been cleaned up.

Differential Revision: https://reviews.llvm.org/D100421
This commit is contained in:
peter klausler 2021-04-13 16:07:58 -07:00
parent 4f42d873c2
commit e81c96d6f8
8 changed files with 46 additions and 44 deletions

View File

@ -220,7 +220,9 @@ static bool DescriptorIO(IoStatementState &io, const Descriptor &descriptor) {
return false;
}
if constexpr (DIR == Direction::Input) {
io.BeginReadingRecord();
if (!io.BeginReadingRecord()) {
return false;
}
}
if (auto *unf{io.get_if<UnformattedIoStatementState<DIR>>()}) {
std::size_t elementBytes{descriptor.ElementBytes()};

View File

@ -894,6 +894,9 @@ bool IONAME(InputUnformattedBlock)(
Cookie cookie, char *x, std::size_t length, std::size_t elementBytes) {
IoStatementState &io{*cookie};
io.BeginReadingRecord();
if (io.GetIoErrorHandler().InError()) {
return false;
}
if (auto *unf{io.get_if<UnformattedIoStatementState<Direction::Input>>()}) {
return unf->Receive(x, length, elementBytes);
}
@ -1037,7 +1040,7 @@ bool IONAME(InputLogical)(Cookie cookie, bool &truth) {
void IONAME(GetIoMsg)(Cookie cookie, char *msg, std::size_t length) {
IoErrorHandler &handler{cookie->GetIoErrorHandler()};
if (handler.GetIoStat()) { // leave "msg" alone when no error
if (handler.InError()) { // leave "msg" alone when no error
handler.GetIoMsg(msg, length);
}
}

View File

@ -17,20 +17,13 @@
namespace Fortran::runtime::io {
void IoErrorHandler::Begin(const char *sourceFileName, int sourceLine) {
flags_ = 0;
ioStat_ = 0;
ioMsg_.reset();
SetLocation(sourceFileName, sourceLine);
}
void IoErrorHandler::SignalError(int iostatOrErrno, const char *msg, ...) {
if (iostatOrErrno == IostatEnd && (flags_ & hasEnd)) {
if (!ioStat_ || ioStat_ < IostatEnd) {
if (ioStat_ == IostatOk || ioStat_ < IostatEnd) {
ioStat_ = IostatEnd;
}
} else if (iostatOrErrno == IostatEor && (flags_ & hasEor)) {
if (!ioStat_ || ioStat_ < IostatEor) {
if (!ioStat_ == IostatOk || ioStat_ < IostatEor) {
ioStat_ = IostatEor; // least priority
}
} else if (iostatOrErrno != IostatOk) {

View File

@ -27,14 +27,13 @@ class IoErrorHandler : public Terminator {
public:
using Terminator::Terminator;
explicit IoErrorHandler(const Terminator &that) : Terminator{that} {}
void Begin(const char *sourceFileName, int sourceLine);
void HasIoStat() { flags_ |= hasIoStat; }
void HasErrLabel() { flags_ |= hasErr; }
void HasEndLabel() { flags_ |= hasEnd; }
void HasEorLabel() { flags_ |= hasEor; }
void HasIoMsg() { flags_ |= hasIoMsg; }
bool InError() const { return ioStat_ != 0; }
bool InError() const { return ioStat_ != IostatOk; }
void SignalError(int iostatOrErrno, const char *msg, ...);
void SignalError(int iostatOrErrno);
@ -58,7 +57,7 @@ private:
hasIoMsg = 16, // IOMSG=
};
std::uint8_t flags_{0};
int ioStat_{0};
int ioStat_{IostatOk};
OwningPtr<char> ioMsg_;
};

View File

@ -230,7 +230,7 @@ int NoUnitIoStatementState::EndIoStatement() {
template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
if constexpr (DIR == Direction::Input) {
BeginReadingRecord(); // in case of READ with no data items
BeginReadingRecord(); // in case there were no I/O items
if (!unit().nonAdvancing) {
FinishReadingRecord();
}
@ -310,12 +310,13 @@ void ExternalIoStatementState<DIR>::HandleRelativePosition(std::int64_t n) {
}
template <Direction DIR>
void ExternalIoStatementState<DIR>::BeginReadingRecord() {
bool ExternalIoStatementState<DIR>::BeginReadingRecord() {
if constexpr (DIR == Direction::Input) {
unit().BeginReadingRecord(*this);
return unit().BeginReadingRecord(*this);
} else {
Crash("ExternalIoStatementState<Direction::Output>::BeginReadingRecord() "
"called");
return false;
}
}
@ -384,8 +385,8 @@ MutableModes &IoStatementState::mutableModes() {
[](auto &x) -> MutableModes & { return x.get().mutableModes(); }, u_);
}
void IoStatementState::BeginReadingRecord() {
std::visit([](auto &x) { return x.get().BeginReadingRecord(); }, u_);
bool IoStatementState::BeginReadingRecord() {
return std::visit([](auto &x) { return x.get().BeginReadingRecord(); }, u_);
}
IoErrorHandler &IoStatementState::GetIoErrorHandler() const {

View File

@ -71,7 +71,7 @@ public:
IoErrorHandler &GetIoErrorHandler() const;
ExternalFileUnit *GetExternalFileUnit() const; // null if internal unit
MutableModes &mutableModes();
void BeginReadingRecord();
bool BeginReadingRecord();
void FinishReadingRecord();
bool Inquire(InquiryKeywordHash, char *, std::size_t);
bool Inquire(InquiryKeywordHash, bool &);
@ -139,7 +139,7 @@ struct IoStatementBase : public DefaultFormatControlCallbacks {
int EndIoStatement();
std::optional<DataEdit> GetNextDataEdit(IoStatementState &, int = 1);
ExternalFileUnit *GetExternalFileUnit() const { return nullptr; }
void BeginReadingRecord() {}
bool BeginReadingRecord() { return true; }
void FinishReadingRecord() {}
bool Inquire(InquiryKeywordHash, char *, std::size_t);
bool Inquire(InquiryKeywordHash, bool &);
@ -282,7 +282,7 @@ public:
void BackspaceRecord();
void HandleRelativePosition(std::int64_t);
void HandleAbsolutePosition(std::int64_t);
void BeginReadingRecord();
bool BeginReadingRecord();
void FinishReadingRecord();
};

View File

@ -352,34 +352,38 @@ void ExternalFileUnit::SetLeftTabLimit() {
positionInRecord = furthestPositionInRecord;
}
void ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
bool 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();
} else if (isFixedRecordLength) {
RUNTIME_CHECK(handler, recordLength.has_value());
auto need{static_cast<std::size_t>(recordOffsetInFrame_ + *recordLength)};
auto got{ReadFrame(frameOffsetInFile_, need, handler)};
if (got < need) {
if (!beganReadingRecord_) {
beganReadingRecord_ = true;
if (access == Access::Sequential) {
if (endfileRecordNumber && currentRecordNumber >= *endfileRecordNumber) {
handler.SignalEnd();
} else if (isFixedRecordLength) {
RUNTIME_CHECK(handler, recordLength.has_value());
auto need{
static_cast<std::size_t>(recordOffsetInFrame_ + *recordLength)};
auto got{ReadFrame(frameOffsetInFile_, need, handler)};
if (got < need) {
handler.SignalEnd();
}
} else if (isUnformatted) {
BeginSequentialVariableUnformattedInputRecord(handler);
} else { // formatted
BeginSequentialVariableFormattedInputRecord(handler);
}
} else if (isUnformatted) {
BeginSequentialVariableUnformattedInputRecord(handler);
} else { // formatted
BeginSequentialVariableFormattedInputRecord(handler);
}
}
RUNTIME_CHECK(handler,
access != Access::Sequential || recordLength.has_value() ||
handler.InError());
return !handler.InError();
}
void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
beganReadingRecord_ = false;
if (handler.GetIoStat() != IostatOk) {
if (handler.InError()) {
// avoid bogus crashes in END/ERR circumstances
} else if (access == Access::Sequential) {
RUNTIME_CHECK(handler, recordLength.has_value());
@ -405,11 +409,11 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
}
bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
bool ok{true};
if (direction_ == Direction::Input) {
FinishReadingRecord(handler);
BeginReadingRecord(handler);
return BeginReadingRecord(handler);
} else { // Direction::Output
bool ok{true};
if (isFixedRecordLength && recordLength) {
// Pad remainder of fixed length record
if (furthestPositionInRecord < *recordLength) {
@ -445,8 +449,8 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
impliedEndfile_ = true;
++currentRecordNumber;
BeginRecord();
return ok;
}
return ok;
}
void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {

View File

@ -77,7 +77,7 @@ public:
bool Receive(char *, std::size_t, std::size_t elementBytes, IoErrorHandler &);
std::optional<char32_t> GetCurrentChar(IoErrorHandler &);
void SetLeftTabLimit();
void BeginReadingRecord(IoErrorHandler &);
bool BeginReadingRecord(IoErrorHandler &);
void FinishReadingRecord(IoErrorHandler &);
bool AdvanceRecord(IoErrorHandler &);
void BackspaceRecord(IoErrorHandler &);