From e81c96d6f8b1cc974f9dbdd47ed82be6be81ae0a Mon Sep 17 00:00:00 2001 From: peter klausler Date: Tue, 13 Apr 2021 16:07:58 -0700 Subject: [PATCH] [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 --- flang/runtime/descriptor-io.h | 4 ++- flang/runtime/io-api.cpp | 5 +++- flang/runtime/io-error.cpp | 11 ++------- flang/runtime/io-error.h | 5 ++-- flang/runtime/io-stmt.cpp | 11 +++++---- flang/runtime/io-stmt.h | 6 ++--- flang/runtime/unit.cpp | 46 +++++++++++++++++++---------------- flang/runtime/unit.h | 2 +- 8 files changed, 46 insertions(+), 44 deletions(-) diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h index 514bcffd19d0..49476682cd72 100644 --- a/flang/runtime/descriptor-io.h +++ b/flang/runtime/descriptor-io.h @@ -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>()}) { std::size_t elementBytes{descriptor.ElementBytes()}; diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp index 57a52bfe6ff0..069e57fdcea3 100644 --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -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>()}) { 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); } } diff --git a/flang/runtime/io-error.cpp b/flang/runtime/io-error.cpp index 58696728c48a..f73272ad6fed 100644 --- 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-error.h b/flang/runtime/io-error.h index 5dd7f5e03d08..e51df9b5be86 100644 --- a/flang/runtime/io-error.h +++ b/flang/runtime/io-error.h @@ -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 ioMsg_; }; diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp index c04013d2d31c..2fd60903a7da 100644 --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -230,7 +230,7 @@ int NoUnitIoStatementState::EndIoStatement() { 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 @@ void ExternalIoStatementState::HandleRelativePosition(std::int64_t n) { } 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 @@ 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 { diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h index 686cc0f4cb0a..000b1ac3238f 100644 --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -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 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(); }; diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp index d5a9f8e53af4..e84385d4e267 100644 --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -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(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 @@ 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) { diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h index ff1506c24109..c9db5fceac5b 100644 --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -77,7 +77,7 @@ public: 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 &);