forked from OSchip/llvm-project
[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:
parent
4f42d873c2
commit
e81c96d6f8
|
@ -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()};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 &);
|
||||
|
|
Loading…
Reference in New Issue