diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h --- a/flang/runtime/descriptor-io.h +++ b/flang/runtime/descriptor-io.h @@ -220,7 +220,9 @@ return false; } if constexpr (DIR == Direction::Input) { - io.BeginReadingRecord(); + if (!io.BeginReadingRecord()) { + return false; + } } if (auto *unf{io.get_if>()}) { std::size_t elementBytes{descriptor.ElementBytes()}; diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -894,6 +894,9 @@ 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>()}) { return unf->Receive(x, length, elementBytes); } @@ -1037,7 +1040,7 @@ 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); } } diff --git a/flang/runtime/io-error.h b/flang/runtime/io-error.h --- a/flang/runtime/io-error.h +++ b/flang/runtime/io-error.h @@ -27,14 +27,13 @@ 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 @@ hasIoMsg = 16, // IOMSG= }; std::uint8_t flags_{0}; - int ioStat_{0}; + int ioStat_{IostatOk}; OwningPtr ioMsg_; }; diff --git a/flang/runtime/io-error.cpp b/flang/runtime/io-error.cpp --- a/flang/runtime/io-error.cpp +++ b/flang/runtime/io-error.cpp @@ -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) { diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -71,7 +71,7 @@ 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 @@ int EndIoStatement(); std::optional 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 @@ void BackspaceRecord(); void HandleRelativePosition(std::int64_t); void HandleAbsolutePosition(std::int64_t); - void BeginReadingRecord(); + bool BeginReadingRecord(); void FinishReadingRecord(); }; diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -230,7 +230,7 @@ template int ExternalIoStatementState::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 @@ } template -void ExternalIoStatementState::BeginReadingRecord() { +bool ExternalIoStatementState::BeginReadingRecord() { if constexpr (DIR == Direction::Input) { - unit().BeginReadingRecord(*this); + return unit().BeginReadingRecord(*this); } else { Crash("ExternalIoStatementState::BeginReadingRecord() " "called"); + return false; } } @@ -384,8 +385,8 @@ [](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 { diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -77,7 +77,7 @@ bool Receive(char *, std::size_t, std::size_t elementBytes, IoErrorHandler &); std::optional GetCurrentChar(IoErrorHandler &); void SetLeftTabLimit(); - void BeginReadingRecord(IoErrorHandler &); + bool BeginReadingRecord(IoErrorHandler &); void FinishReadingRecord(IoErrorHandler &); bool AdvanceRecord(IoErrorHandler &); void BackspaceRecord(IoErrorHandler &); diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -352,34 +352,38 @@ 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(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(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 @@ } 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 @@ impliedEndfile_ = true; ++currentRecordNumber; BeginRecord(); + return ok; } - return ok; } void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {