[flang-commits] [flang] cd0a122 - [flang] Fix "non-advancing" I/O, support $ in FORMAT
peter klausler via flang-commits
flang-commits at lists.llvm.org
Mon Jun 28 12:18:35 PDT 2021
Author: peter klausler
Date: 2021-06-28T12:18:25-07:00
New Revision: cd0a1226b50081e86eb75a89d01e8782423971a0
URL: https://github.com/llvm/llvm-project/commit/cd0a1226b50081e86eb75a89d01e8782423971a0
DIFF: https://github.com/llvm/llvm-project/commit/cd0a1226b50081e86eb75a89d01e8782423971a0.diff
LOG: [flang] Fix "non-advancing" I/O, support $ in FORMAT
Non-advancing I/O was failing; ExternalFileUnit was losing
track of what writes had been committed to the file. Fixed.
Also, support the common extension of $ and \ in a FORMAT
as being equivalent to ADVANCE=NO.
Differential Revision: https://reviews.llvm.org/D105046
Added:
Modified:
flang/runtime/connection.h
flang/runtime/format-implementation.h
flang/runtime/format.h
flang/runtime/io-api.cpp
flang/runtime/io-stmt.cpp
flang/runtime/io-stmt.h
flang/runtime/unit-map.cpp
flang/runtime/unit.cpp
flang/runtime/unit.h
Removed:
################################################################################
diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index 6eb6b62ccab7e..6d0678f18abfa 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -49,7 +49,6 @@ struct ConnectionState : public ConnectionAttributes {
std::int64_t currentRecordNumber{1}; // 1 is first
std::int64_t positionInRecord{0}; // offset in current record
std::int64_t furthestPositionInRecord{0}; // max(position+bytes)
- bool nonAdvancing{false}; // ADVANCE='NO'
// Set at end of non-advancing I/O data transfer
std::optional<std::int64_t> leftTabLimit; // offset in current record
diff --git a/flang/runtime/format-implementation.h b/flang/runtime/format-implementation.h
index 63ca682eb3e7a..8c41a984693fa 100644
--- a/flang/runtime/format-implementation.h
+++ b/flang/runtime/format-implementation.h
@@ -357,6 +357,8 @@ int FormatControl<CONTEXT>::CueUpNextDataEdit(Context &context, bool stop) {
}
} else if (ch == '/') {
context.AdvanceRecord(repeat && *repeat > 0 ? *repeat : 1);
+ } else if (ch == '$' || ch == '\\') {
+ context.mutableModes().nonAdvancing = true;
} else {
context.SignalError(IostatErrorInFormat,
"Invalid character '%c' in FORMAT", static_cast<char>(ch));
diff --git a/flang/runtime/format.h b/flang/runtime/format.h
index 77daa38f3262e..1989aa79a98ee 100644
--- a/flang/runtime/format.h
+++ b/flang/runtime/format.h
@@ -35,6 +35,7 @@ struct MutableModes {
char delim{'\0'}; // DELIM=
short scale{0}; // kP
bool inNamelist{false}; // skip ! comments
+ bool nonAdvancing{false}; // ADVANCE='NO', or $ or \ in FORMAT
};
// A single edit descriptor extracted from a FORMAT
diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index d1b13cb330eba..8996b44669dda 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -437,12 +437,13 @@ static bool YesOrNo(const char *keyword, std::size_t length, const char *what,
bool IONAME(SetAdvance)(
Cookie cookie, const char *keyword, std::size_t length) {
IoStatementState &io{*cookie};
- ConnectionState &connection{io.GetConnectionState()};
- connection.nonAdvancing =
- !YesOrNo(keyword, length, "ADVANCE", io.GetIoErrorHandler());
- if (connection.nonAdvancing && connection.access == Access::Direct) {
+ bool nonAdvancing{
+ !YesOrNo(keyword, length, "ADVANCE", io.GetIoErrorHandler())};
+ if (nonAdvancing && io.GetConnectionState().access == Access::Direct) {
io.GetIoErrorHandler().SignalError(
"Non-advancing I/O attempted on direct access file");
+ } else {
+ io.mutableModes().nonAdvancing = nonAdvancing;
}
return true;
}
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 3432f847cce51..56ea6129d5501 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -203,9 +203,8 @@ MutableModes &ExternalIoStatementBase::mutableModes() { return unit_.modes; }
ConnectionState &ExternalIoStatementBase::GetConnectionState() { return unit_; }
int ExternalIoStatementBase::EndIoStatement() {
- if (unit_.nonAdvancing) {
+ if (mutableModes().nonAdvancing) {
unit_.leftTabLimit = unit_.furthestPositionInRecord;
- unit_.nonAdvancing = false;
} else {
unit_.leftTabLimit.reset();
}
@@ -260,14 +259,20 @@ int NoUnitIoStatementState::EndIoStatement() {
return result;
}
+template <Direction DIR>
+ExternalIoStatementState<DIR>::ExternalIoStatementState(
+ ExternalFileUnit &unit, const char *sourceFile, int sourceLine)
+ : ExternalIoStatementBase{unit, sourceFile, sourceLine}, mutableModes_{
+ unit.modes} {}
+
template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
if constexpr (DIR == Direction::Input) {
BeginReadingRecord(); // in case there were no I/O items
- if (!unit().nonAdvancing) {
+ if (!mutableModes().nonAdvancing) {
FinishReadingRecord();
}
} else {
- if (!unit().nonAdvancing) {
+ if (!mutableModes().nonAdvancing) {
unit().AdvanceRecord(*this);
}
unit().FlushIfTerminal(*this);
@@ -375,7 +380,7 @@ ExternalFormattedIoStatementState<DIR, CHAR>::ExternalFormattedIoStatementState(
ExternalFileUnit &unit, const CHAR *format, std::size_t formatLength,
const char *sourceFile, int sourceLine)
: ExternalIoStatementState<DIR>{unit, sourceFile, sourceLine},
- mutableModes_{unit.modes}, format_{*this, format, formatLength} {}
+ format_{*this, format, formatLength} {}
template <Direction DIR, typename CHAR>
int ExternalFormattedIoStatementState<DIR, CHAR>::EndIoStatement() {
@@ -558,7 +563,7 @@ std::optional<char32_t> IoStatementState::NextInField(
return std::optional<char32_t>{' '};
}
IoErrorHandler &handler{GetIoErrorHandler()};
- if (connection.nonAdvancing) {
+ if (mutableModes().nonAdvancing) {
handler.SignalEor();
} else {
handler.SignalError(IostatRecordReadOverrun);
@@ -867,7 +872,7 @@ int ExternalMiscIoStatementState::EndIoStatement() {
ExternalFileUnit &ext{unit()};
switch (which_) {
case Flush:
- ext.Flush(*this);
+ ext.FlushOutput(*this);
std::fflush(nullptr); // flushes C stdio output streams (12.9(2))
break;
case Backspace:
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 34c4a47363c0d..49964359a48ba 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -320,7 +320,9 @@ template <Direction DIR>
class ExternalIoStatementState : public ExternalIoStatementBase,
public IoDirectionState<DIR> {
public:
- using ExternalIoStatementBase::ExternalIoStatementBase;
+ ExternalIoStatementState(
+ ExternalFileUnit &, const char *sourceFile = nullptr, int sourceLine = 0);
+ MutableModes &mutableModes() { return mutableModes_; }
int EndIoStatement();
bool Emit(const char *, std::size_t, std::size_t elementBytes);
bool Emit(const char *, std::size_t);
@@ -333,6 +335,12 @@ class ExternalIoStatementState : public ExternalIoStatementBase,
void HandleAbsolutePosition(std::int64_t);
bool BeginReadingRecord();
void FinishReadingRecord();
+
+private:
+ // These are forked from ConnectionState's modes at the beginning
+ // of each formatted I/O statement so they may be overridden by control
+ // edit descriptors during the statement.
+ MutableModes mutableModes_;
};
template <Direction DIR, typename CHAR>
@@ -343,7 +351,6 @@ class ExternalFormattedIoStatementState : public ExternalIoStatementState<DIR>,
ExternalFormattedIoStatementState(ExternalFileUnit &, const CharType *format,
std::size_t formatLength, const char *sourceFile = nullptr,
int sourceLine = 0);
- MutableModes &mutableModes() { return mutableModes_; }
int EndIoStatement();
std::optional<DataEdit> GetNextDataEdit(
IoStatementState &, int maxRepeat = 1) {
@@ -351,10 +358,6 @@ class ExternalFormattedIoStatementState : public ExternalIoStatementState<DIR>,
}
private:
- // These are forked from ConnectionState's modes at the beginning
- // of each formatted I/O statement so they may be overridden by control
- // edit descriptors during the statement.
- MutableModes mutableModes_;
FormatControl<ExternalFormattedIoStatementState> format_;
};
diff --git a/flang/runtime/unit-map.cpp b/flang/runtime/unit-map.cpp
index 915c747371850..2a7e414b3facc 100644
--- a/flang/runtime/unit-map.cpp
+++ b/flang/runtime/unit-map.cpp
@@ -67,7 +67,7 @@ void UnitMap::FlushAll(IoErrorHandler &handler) {
CriticalSection critical{lock_};
for (int j{0}; j < buckets_; ++j) {
for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) {
- p->unit.Flush(handler);
+ p->unit.FlushOutput(handler);
}
}
}
diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index aafb71fb6d73c..e1ff6e7fd2930 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -32,7 +32,7 @@ void FlushOutputOnCrash(const Terminator &terminator) {
if (defaultOutput) {
IoErrorHandler handler{terminator};
handler.HasIoStat(); // prevent nested crash if flush has error
- defaultOutput->Flush(handler);
+ defaultOutput->FlushOutput(handler);
}
}
@@ -118,7 +118,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
}
// Otherwise, OPEN on open unit with new FILE= implies CLOSE
DoImpliedEndfile(handler);
- Flush(handler);
+ FlushOutput(handler);
Close(CloseStatus::Keep, handler);
}
set_path(std::move(newPath), newPathLength);
@@ -168,7 +168,7 @@ void ExternalFileUnit::OpenAnonymousUnit(std::optional<OpenStatus> status,
void ExternalFileUnit::CloseUnit(CloseStatus status, IoErrorHandler &handler) {
DoImpliedEndfile(handler);
- Flush(handler);
+ FlushOutput(handler);
Close(status, handler);
}
@@ -462,12 +462,9 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
}
}
- frameOffsetInFile_ +=
- recordOffsetInFrame_ + recordLength.value_or(furthestPositionInRecord);
- recordOffsetInFrame_ = 0;
+ CommitWrites();
impliedEndfile_ = true;
++currentRecordNumber;
- BeginRecord();
return ok;
}
}
@@ -499,9 +496,24 @@ void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
}
}
+void ExternalFileUnit::FlushOutput(IoErrorHandler &handler) {
+ if (!mayPosition()) {
+ auto frameAt{FrameAt()};
+ if (frameOffsetInFile_ >= frameAt &&
+ frameOffsetInFile_ <
+ static_cast<std::int64_t>(frameAt + FrameLength())) {
+ // A Flush() that's about to happen to a non-positionable file
+ // needs to advance frameOffsetInFile_ to prevent attempts at
+ // impossible seeks
+ CommitWrites();
+ }
+ }
+ Flush(handler);
+}
+
void ExternalFileUnit::FlushIfTerminal(IoErrorHandler &handler) {
if (isTerminal()) {
- Flush(handler);
+ FlushOutput(handler);
}
}
@@ -533,8 +545,6 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
}
void ExternalFileUnit::EndIoStatement() {
- frameOffsetInFile_ += recordOffsetInFrame_;
- recordOffsetInFrame_ = 0;
io_.reset();
u_.emplace<std::monostate>();
lock_.Drop();
@@ -585,7 +595,7 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
void ExternalFileUnit::BeginSequentialVariableFormattedInputRecord(
IoErrorHandler &handler) {
if (this == defaultInput && defaultOutput) {
- defaultOutput->Flush(handler);
+ defaultOutput->FlushOutput(handler);
}
std::size_t length{0};
do {
@@ -701,6 +711,13 @@ void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) {
impliedEndfile_ = false;
}
+void ExternalFileUnit::CommitWrites() {
+ frameOffsetInFile_ +=
+ recordOffsetInFrame_ + recordLength.value_or(furthestPositionInRecord);
+ recordOffsetInFrame_ = 0;
+ BeginRecord();
+}
+
ChildIo &ExternalFileUnit::PushChildIo(IoStatementState &parent) {
OwningPtr<ChildIo> current{std::move(child_)};
Terminator &terminator{parent.GetIoErrorHandler()};
diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index 68876ff536399..99ba05d78bee6 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -82,6 +82,7 @@ class ExternalFileUnit : public ConnectionState,
void FinishReadingRecord(IoErrorHandler &);
bool AdvanceRecord(IoErrorHandler &);
void BackspaceRecord(IoErrorHandler &);
+ void FlushOutput(IoErrorHandler &);
void FlushIfTerminal(IoErrorHandler &);
void Endfile(IoErrorHandler &);
void Rewind(IoErrorHandler &);
@@ -107,6 +108,7 @@ class ExternalFileUnit : public ConnectionState,
bool SetSequentialVariableFormattedRecordLength();
void DoImpliedEndfile(IoErrorHandler &);
void DoEndfile(IoErrorHandler &);
+ void CommitWrites();
int unitNumber_{-1};
Direction direction_{Direction::Output};
More information about the flang-commits
mailing list