[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