[flang-commits] [flang] 4e53e28 - Revert "[flang] Debugging of ACCESS='STREAM' I/O"

Andrzej Warzynski via flang-commits flang-commits at lists.llvm.org
Thu Feb 3 07:19:54 PST 2022


Author: Andrzej Warzynski
Date: 2022-02-03T15:19:42Z
New Revision: 4e53e283744b1a314948b1ca139c09811121f70e

URL: https://github.com/llvm/llvm-project/commit/4e53e283744b1a314948b1ca139c09811121f70e
DIFF: https://github.com/llvm/llvm-project/commit/4e53e283744b1a314948b1ca139c09811121f70e.diff

LOG: Revert "[flang] Debugging of ACCESS='STREAM' I/O"

This reverts commit be9946b877add0db906090d22840b213c3f41dd2.

This change has caused Flang's Windows buildbot to start failing:
* https://lab.llvm.org/buildbot/#/builders/172/builds/7664

Added: 
    

Modified: 
    flang/include/flang/Runtime/iostat.h
    flang/runtime/connection.h
    flang/runtime/edit-input.cpp
    flang/runtime/file.h
    flang/runtime/io-api.cpp
    flang/runtime/io-stmt.cpp
    flang/runtime/io-stmt.h
    flang/runtime/iostat.cpp
    flang/runtime/unit.cpp
    flang/runtime/unit.h

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h
index 07a25c420425..ec1c6a2abdbe 100644
--- a/flang/include/flang/Runtime/iostat.h
+++ b/flang/include/flang/Runtime/iostat.h
@@ -45,7 +45,7 @@ enum Iostat {
   IostatInternalWriteOverrun,
   IostatErrorInFormat,
   IostatErrorInKeyword,
-  IostatEndfileDirect,
+  IostatEndfileNonSequential,
   IostatEndfileUnwritable,
   IostatOpenBadRecl,
   IostatOpenUnknownSize,

diff  --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index b36f7d1eef36..c812312de91d 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -22,6 +22,8 @@ class IoStatementState;
 enum class Direction { Output, Input };
 enum class Access { Sequential, Direct, Stream };
 
+inline bool IsRecordFile(Access a) { return a != Access::Stream; }
+
 // These characteristics of a connection are immutable after being
 // established in an OPEN statement.
 struct ConnectionAttributes {
@@ -29,11 +31,6 @@ struct ConnectionAttributes {
   std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true
   bool isUTF8{false}; // ENCODING='UTF-8'
   std::optional<std::int64_t> openRecl; // RECL= on OPEN
-
-  bool IsRecordFile() const {
-    // Formatted stream files are viewed as having records, at least on input
-    return access != Access::Stream || !isUnformatted.value_or(true);
-  }
 };
 
 struct ConnectionState : public ConnectionAttributes {

diff  --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 2e9cd80aa6f9..3460661cc427 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -19,7 +19,7 @@ static bool EditBOZInput(IoStatementState &io, const DataEdit &edit, void *n,
   std::optional<int> remaining;
   std::optional<char32_t> next{io.PrepareInput(edit, remaining)};
   common::UnsignedInt128 value{0};
-  for (; next; next = io.NextInField(remaining, edit)) {
+  for (; next; next = io.NextInField(remaining)) {
     char32_t ch{*next};
     if (ch == ' ' || ch == '\t') {
       continue;
@@ -63,7 +63,7 @@ static bool ScanNumericPrefix(IoStatementState &io, const DataEdit &edit,
     if (negative || *next == '+') {
       io.GotChar();
       io.SkipSpaces(remaining);
-      next = io.NextInField(remaining, edit);
+      next = io.NextInField(remaining, GetDecimalPoint(edit));
     }
   }
   return negative;
@@ -101,7 +101,7 @@ bool EditIntegerInput(
   bool negate{ScanNumericPrefix(io, edit, next, remaining)};
   common::UnsignedInt128 value{0};
   bool any{negate};
-  for (; next; next = io.NextInField(remaining, edit)) {
+  for (; next; next = io.NextInField(remaining)) {
     char32_t ch{*next};
     if (ch == ' ' || ch == '\t') {
       if (edit.modes.editingFlags & blankZero) {
@@ -167,7 +167,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     // Subtle: a blank field of digits could be followed by 'E' or 'D',
     for (; next &&
          ((*next >= 'a' && *next <= 'z') || (*next >= 'A' && *next <= 'Z'));
-         next = io.NextInField(remaining, edit)) {
+         next = io.NextInField(remaining)) {
       if (*next >= 'a' && *next <= 'z') {
         Put(*next - 'a' + 'A');
       } else {
@@ -176,7 +176,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     }
     if (next && *next == '(') { // NaN(...)
       while (next && *next != ')') {
-        next = io.NextInField(remaining, edit);
+        next = io.NextInField(remaining);
       }
     }
     exponent = 0;
@@ -185,7 +185,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     Put('.'); // input field is normalized to a fraction
     auto start{got};
     bool bzMode{(edit.modes.editingFlags & blankZero) != 0};
-    for (; next; next = io.NextInField(remaining, edit)) {
+    for (; next; next = io.NextInField(remaining, decimal)) {
       char32_t ch{*next};
       if (ch == ' ' || ch == '\t') {
         if (bzMode) {
@@ -214,7 +214,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
       // Optional exponent letter.  Blanks are allowed between the
       // optional exponent letter and the exponent value.
       io.SkipSpaces(remaining);
-      next = io.NextInField(remaining, edit);
+      next = io.NextInField(remaining);
     }
     // The default exponent is -kP, but the scale factor doesn't affect
     // an explicit exponent.
@@ -224,9 +224,9 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
             (bzMode && (*next == ' ' || *next == '\t')))) {
       bool negExpo{*next == '-'};
       if (negExpo || *next == '+') {
-        next = io.NextInField(remaining, edit);
+        next = io.NextInField(remaining);
       }
-      for (exponent = 0; next; next = io.NextInField(remaining, edit)) {
+      for (exponent = 0; next; next = io.NextInField(remaining)) {
         if (*next >= '0' && *next <= '9') {
           exponent = 10 * exponent + *next - '0';
         } else if (bzMode && (*next == ' ' || *next == '\t')) {
@@ -257,7 +257,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
   // input value.
   if (edit.descriptor == DataEdit::ListDirectedImaginaryPart) {
     if (next && (*next == ' ' || *next == '\t')) {
-      next = io.NextInField(remaining, edit);
+      next = io.NextInField(remaining);
     }
     if (!next) { // NextInField fails on separators like ')'
       next = io.GetCurrentChar();
@@ -267,7 +267,7 @@ static int ScanRealInput(char *buffer, int bufferSize, IoStatementState &io,
     }
   } else if (remaining) {
     while (next && (*next == ' ' || *next == '\t')) {
-      next = io.NextInField(remaining, edit);
+      next = io.NextInField(remaining);
     }
     if (next) {
       return 0; // error: unused nonblank character in fixed-width field
@@ -457,7 +457,7 @@ bool EditLogicalInput(IoStatementState &io, const DataEdit &edit, bool &x) {
   std::optional<int> remaining;
   std::optional<char32_t> next{io.PrepareInput(edit, remaining)};
   if (next && *next == '.') { // skip optional period
-    next = io.NextInField(remaining, edit);
+    next = io.NextInField(remaining);
   }
   if (!next) {
     io.GetIoErrorHandler().SignalError("Empty LOGICAL input field");
@@ -480,7 +480,7 @@ bool EditLogicalInput(IoStatementState &io, const DataEdit &edit, bool &x) {
   if (remaining) { // ignore the rest of the field
     io.HandleRelativePosition(*remaining);
   } else if (edit.descriptor == DataEdit::ListDirected) {
-    while (io.NextInField(remaining, edit)) { // discard rest of field
+    while (io.NextInField(remaining)) { // discard rest of field
     }
   }
   return true;
@@ -520,7 +520,7 @@ static bool EditDelimitedCharacterInput(
 }
 
 static bool EditListDirectedDefaultCharacterInput(
-    IoStatementState &io, char *x, std::size_t length, const DataEdit &edit) {
+    IoStatementState &io, char *x, std::size_t length) {
   auto ch{io.GetCurrentChar()};
   if (ch && (*ch == '\'' || *ch == '"')) {
     io.HandleRelativePosition(1);
@@ -532,7 +532,8 @@ static bool EditListDirectedDefaultCharacterInput(
   // Undelimited list-directed character input: stop at a value separator
   // or the end of the current record.
   std::optional<int> remaining{length};
-  while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) {
+  for (std::optional<char32_t> next{io.NextInField(remaining)}; next;
+       next = io.NextInField(remaining)) {
     switch (*next) {
     case ' ':
     case '\t':
@@ -554,7 +555,7 @@ bool EditDefaultCharacterInput(
     IoStatementState &io, const DataEdit &edit, char *x, std::size_t length) {
   switch (edit.descriptor) {
   case DataEdit::ListDirected:
-    return EditListDirectedDefaultCharacterInput(io, x, length, edit);
+    return EditListDirectedDefaultCharacterInput(io, x, length);
   case 'A':
   case 'G':
     break;
@@ -575,7 +576,8 @@ bool EditDefaultCharacterInput(
   // characters.  When the variable is wider than the field, there's
   // trailing padding.
   std::int64_t skip{*remaining - static_cast<std::int64_t>(length)};
-  while (std::optional<char32_t> next{io.NextInField(remaining, edit)}) {
+  for (std::optional<char32_t> next{io.NextInField(remaining)}; next;
+       next = io.NextInField(remaining)) {
     if (skip > 0) {
       --skip;
       io.GotChar(-1);

diff  --git a/flang/runtime/file.h b/flang/runtime/file.h
index c61ed798289c..137d643f74ae 100644
--- a/flang/runtime/file.h
+++ b/flang/runtime/file.h
@@ -35,6 +35,7 @@ class OpenFile {
   bool mayPosition() const { return mayPosition_; }
   bool mayAsynchronous() const { return mayAsynchronous_; }
   void set_mayAsynchronous(bool yes) { mayAsynchronous_ = yes; }
+  FileOffset position() const { return position_; }
   bool isTerminal() const { return isTerminal_; }
   std::optional<FileOffset> knownSize() const { return knownSize_; }
 

diff  --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp
index 8c999edba5c9..345577d2d675 100644
--- a/flang/runtime/io-api.cpp
+++ b/flang/runtime/io-api.cpp
@@ -524,17 +524,18 @@ bool IONAME(SetPad)(Cookie cookie, const char *keyword, std::size_t length) {
 bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) {
   IoStatementState &io{*cookie};
   ConnectionState &connection{io.GetConnectionState()};
-  IoErrorHandler &handler{io.GetIoErrorHandler()};
   if (connection.access != Access::Stream) {
-    handler.SignalError("POS= may not appear unless ACCESS='STREAM'");
+    io.GetIoErrorHandler().SignalError(
+        "POS= may not appear unless ACCESS='STREAM'");
     return false;
   }
-  if (pos < 1) { // POS=1 is beginning of file (12.6.2.11)
-    handler.SignalError("POS=%zd is invalid", static_cast<std::intmax_t>(pos));
+  if (pos < 1) {
+    io.GetIoErrorHandler().SignalError(
+        "POS=%zd is invalid", static_cast<std::intmax_t>(pos));
     return false;
   }
   if (auto *unit{io.GetExternalFileUnit()}) {
-    unit->SetPosition(pos - 1, handler);
+    unit->SetPosition(pos);
     return true;
   }
   io.GetIoErrorHandler().Crash("SetPos() on internal unit");
@@ -544,22 +545,23 @@ bool IONAME(SetPos)(Cookie cookie, std::int64_t pos) {
 bool IONAME(SetRec)(Cookie cookie, std::int64_t rec) {
   IoStatementState &io{*cookie};
   ConnectionState &connection{io.GetConnectionState()};
-  IoErrorHandler &handler{io.GetIoErrorHandler()};
   if (connection.access != Access::Direct) {
-    handler.SignalError("REC= may not appear unless ACCESS='DIRECT'");
+    io.GetIoErrorHandler().SignalError(
+        "REC= may not appear unless ACCESS='DIRECT'");
     return false;
   }
   if (!connection.openRecl) {
-    handler.SignalError("RECL= was not specified");
+    io.GetIoErrorHandler().SignalError("RECL= was not specified");
     return false;
   }
   if (rec < 1) {
-    handler.SignalError("REC=%zd is invalid", static_cast<std::intmax_t>(rec));
+    io.GetIoErrorHandler().SignalError(
+        "REC=%zd is invalid", static_cast<std::intmax_t>(rec));
     return false;
   }
   connection.currentRecordNumber = rec;
   if (auto *unit{io.GetExternalFileUnit()}) {
-    unit->SetPosition((rec - 1) * *connection.openRecl, handler);
+    unit->SetPosition((rec - 1) * *connection.openRecl);
   }
   return true;
 }

diff  --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 7d447bafa880..52d0a1ebe6a3 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -268,7 +268,7 @@ ExternalIoStatementState<DIR>::ExternalIoStatementState(
     : ExternalIoStatementBase{unit, sourceFile, sourceLine}, mutableModes_{
                                                                  unit.modes} {
   if constexpr (DIR == Direction::Output) {
-    // If the last statement was a non-advancing IO input statement, the unit
+    // If the last statement was a non advancing IO input statement, the unit
     // furthestPositionInRecord was not advanced, but the positionInRecord may
     // have been advanced. Advance furthestPositionInRecord here to avoid
     // overwriting the part of the record that has been read with blanks.
@@ -505,66 +505,6 @@ bool IoStatementState::EmitField(
   }
 }
 
-std::optional<char32_t> IoStatementState::NextInField(
-    std::optional<int> &remaining, const DataEdit &edit) {
-  if (!remaining) { // Stream, list-directed, or NAMELIST
-    if (auto next{GetCurrentChar()}) {
-      if (edit.IsListDirected()) {
-        // list-directed or NAMELIST: check for separators
-        switch (*next) {
-        case ' ':
-        case '\t':
-        case ';':
-        case '/':
-        case '(':
-        case ')':
-        case '\'':
-        case '"':
-        case '*':
-        case '\n': // for stream access
-          return std::nullopt;
-        case ',':
-          if (edit.modes.editingFlags & decimalComma) {
-            break;
-          } else {
-            return std::nullopt;
-          }
-        default:
-          break;
-        }
-      }
-      HandleRelativePosition(1);
-      GotChar();
-      return next;
-    }
-  } else if (*remaining > 0) {
-    if (auto next{GetCurrentChar()}) {
-      --*remaining;
-      HandleRelativePosition(1);
-      GotChar();
-      return next;
-    }
-    const ConnectionState &connection{GetConnectionState()};
-    if (!connection.IsAtEOF()) {
-      if (auto length{connection.EffectiveRecordLength()}) {
-        if (connection.positionInRecord >= *length) {
-          IoErrorHandler &handler{GetIoErrorHandler()};
-          if (mutableModes().nonAdvancing) {
-            handler.SignalEor();
-          } else if (connection.openRecl && !connection.modes.pad) {
-            handler.SignalError(IostatRecordReadOverrun);
-          }
-          if (connection.modes.pad) { // PAD='YES'
-            --*remaining;
-            return std::optional<char32_t>{' '};
-          }
-        }
-      }
-    }
-  }
-  return std::nullopt;
-}
-
 bool IoStatementState::Inquire(
     InquiryKeywordHash inquiry, char *out, std::size_t chars) {
   return std::visit(
@@ -1120,7 +1060,7 @@ bool InquireUnitState::Inquire(
     result = unit().IsConnected() ? unit().unitNumber() : -1;
     return true;
   case HashInquiryKeyword("POS"):
-    result = unit().InquirePos();
+    result = unit().position();
     return true;
   case HashInquiryKeyword("RECL"):
     if (!unit().IsConnected()) {

diff  --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index 59d4e50460fb..93b3bed73294 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -142,7 +142,7 @@ class IoStatementState {
       }
       SkipSpaces(remaining);
     }
-    return NextInField(remaining, edit);
+    return NextInField(remaining);
   }
 
   std::optional<char32_t> SkipSpaces(std::optional<int> &remaining) {
@@ -163,10 +163,59 @@ class IoStatementState {
     return std::nullopt;
   }
 
-  // Acquires the next input character, respecting any applicable field width
-  // or separator character.
   std::optional<char32_t> NextInField(
-      std::optional<int> &remaining, const DataEdit &);
+      std::optional<int> &remaining, char32_t decimal = '.') {
+    if (!remaining) { // list-directed or NAMELIST: check for separators
+      if (auto next{GetCurrentChar()}) {
+        if (*next == decimal) { // can be ','
+          HandleRelativePosition(1);
+          return next;
+        }
+        switch (*next) {
+        case ' ':
+        case '\t':
+        case ',':
+        case ';':
+        case '/':
+        case '(':
+        case ')':
+        case '\'':
+        case '"':
+        case '*':
+        case '\n': // for stream access
+          break;
+        default:
+          HandleRelativePosition(1);
+          return next;
+        }
+      }
+    } else if (*remaining > 0) {
+      if (auto next{GetCurrentChar()}) {
+        --*remaining;
+        HandleRelativePosition(1);
+        GotChar();
+        return next;
+      }
+      const ConnectionState &connection{GetConnectionState()};
+      if (!connection.IsAtEOF()) {
+        if (auto length{connection.EffectiveRecordLength()}) {
+          if (connection.positionInRecord >= *length) {
+            IoErrorHandler &handler{GetIoErrorHandler()};
+            if (mutableModes().nonAdvancing) {
+              handler.SignalEor();
+            } else if (connection.openRecl && !connection.modes.pad) {
+              handler.SignalError(IostatRecordReadOverrun);
+            }
+            if (connection.modes.pad) { // PAD='YES'
+              --*remaining;
+              return std::optional<char32_t>{' '};
+            }
+          }
+        }
+      }
+    }
+    return std::nullopt;
+  }
 
   // Skips spaces, advances records, and ignores NAMELIST comments
   std::optional<char32_t> GetNextNonBlank() {

diff  --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp
index 58e3f1b387e1..d58ad6261ac6 100644
--- a/flang/runtime/iostat.cpp
+++ b/flang/runtime/iostat.cpp
@@ -33,8 +33,8 @@ const char *IostatErrorString(int iostat) {
     return "Invalid FORMAT";
   case IostatErrorInKeyword:
     return "Bad keyword argument value";
-  case IostatEndfileDirect:
-    return "ENDFILE on direct-access file";
+  case IostatEndfileNonSequential:
+    return "ENDFILE on non-sequential file";
   case IostatEndfileUnwritable:
     return "ENDFILE on read-only file";
   case IostatOpenBadRecl:

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 3fbb397d996b..363565da6833 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -151,7 +151,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
   if (totalBytes && access == Access::Direct && openRecl.value_or(0) > 0) {
     endfileRecordNumber = 1 + (*totalBytes / *openRecl);
   }
-  if (position == Position::Append && access != Access::Stream) {
+  if (position == Position::Append) {
     if (!endfileRecordNumber) {
       // Fake it so that we can backspace relative from the end
       endfileRecordNumber = std::numeric_limits<std::int64_t>::max() - 2;
@@ -348,10 +348,8 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes,
     furthestPositionInRecord = furthestAfter;
     return true;
   } else {
-    handler.SignalEnd();
-    if (access == Access::Sequential) {
-      endfileRecordNumber = currentRecordNumber;
-    }
+    // EOF or error: can be handled & has been signaled
+    endfileRecordNumber = currentRecordNumber;
     return false;
   }
 }
@@ -385,20 +383,18 @@ const char *ExternalFileUnit::FrameNextInput(
     auto at{recordOffsetInFrame_ + positionInRecord};
     auto need{static_cast<std::size_t>(at + bytes)};
     auto got{ReadFrame(frameOffsetInFile_, need, handler)};
-    SetVariableFormattedRecordLength();
+    SetSequentialVariableFormattedRecordLength();
     if (got >= need) {
       return Frame() + at;
     }
     handler.SignalEnd();
-    if (access == Access::Sequential) {
-      endfileRecordNumber = currentRecordNumber;
-    }
+    endfileRecordNumber = currentRecordNumber;
   }
   return nullptr;
 }
 
-bool ExternalFileUnit::SetVariableFormattedRecordLength() {
-  if (recordLength || access == Access::Direct) {
+bool ExternalFileUnit::SetSequentialVariableFormattedRecordLength() {
+  if (recordLength || access != Access::Sequential) {
     return true;
   } else if (FrameLength() > recordOffsetInFrame_) {
     const char *record{Frame() + recordOffsetInFrame_};
@@ -434,24 +430,22 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
         recordLength.reset();
         handler.SignalEnd();
       }
-    } else {
+    } else if (access == Access::Sequential) {
       recordLength.reset();
       if (IsAtEOF()) {
         handler.SignalEnd();
       } else {
         RUNTIME_CHECK(handler, isUnformatted.has_value());
-        if (*isUnformatted) {
-          if (access == Access::Sequential) {
-            BeginSequentialVariableUnformattedInputRecord(handler);
-          }
-        } else { // formatted sequential or stream
-          BeginVariableFormattedInputRecord(handler);
+        if (isUnformatted.value_or(false)) {
+          BeginSequentialVariableUnformattedInputRecord(handler);
+        } else { // formatted
+          BeginSequentialVariableFormattedInputRecord(handler);
         }
       }
     }
   }
   RUNTIME_CHECK(handler,
-      recordLength.has_value() || !IsRecordFile() || handler.InError());
+      recordLength.has_value() || !IsRecordFile(access) || handler.InError());
   return !handler.InError();
 }
 
@@ -459,15 +453,14 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
   RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
   beganReadingRecord_ = false;
   if (handler.InError() && handler.GetIoStat() != IostatEor) {
-    // Avoid bogus crashes in END/ERR circumstances; but
-    // still increment the current record number so that
-    // an attempted read of an endfile record, followed by
-    // a BACKSPACE, will still be at EOF.
-    ++currentRecordNumber;
-  } else if (IsRecordFile()) {
+    // avoid bogus crashes in END/ERR circumstances
+  } else if (access == Access::Sequential) {
     RUNTIME_CHECK(handler, recordLength.has_value());
     recordOffsetInFrame_ += *recordLength;
-    if (access != Access::Direct) {
+    if (openRecl && access == Access::Direct) {
+      frameOffsetInFile_ += recordOffsetInFrame_;
+      recordOffsetInFrame_ = 0;
+    } else {
       RUNTIME_CHECK(handler, isUnformatted.has_value());
       recordLength.reset();
       if (isUnformatted.value_or(false)) {
@@ -489,12 +482,8 @@ void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
         }
       }
     }
-    ++currentRecordNumber;
-  } else { // unformatted stream
-    furthestPositionInRecord =
-        std::max(furthestPositionInRecord, positionInRecord);
-    frameOffsetInFile_ += recordOffsetInFrame_ + furthestPositionInRecord;
   }
+  ++currentRecordNumber;
   BeginRecord();
 }
 
@@ -505,10 +494,8 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
   } else { // Direction::Output
     bool ok{true};
     RUNTIME_CHECK(handler, isUnformatted.has_value());
-    positionInRecord = furthestPositionInRecord;
-    if (access == Access::Direct) {
-      if (furthestPositionInRecord <
-          openRecl.value_or(furthestPositionInRecord)) {
+    if (openRecl && access == Access::Direct) {
+      if (furthestPositionInRecord < *openRecl) {
         // Pad remainder of fixed length record
         WriteFrame(
             frameOffsetInFile_, recordOffsetInFrame_ + *openRecl, handler);
@@ -517,8 +504,9 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
             *openRecl - furthestPositionInRecord);
         furthestPositionInRecord = *openRecl;
       }
-    } else if (*isUnformatted) {
-      if (access == Access::Sequential) {
+    } else {
+      positionInRecord = furthestPositionInRecord;
+      if (isUnformatted.value_or(false)) {
         // Append the length of a sequential unformatted variable-length record
         // as its footer, then overwrite the reserved first four bytes of the
         // record with its length as its header.  These four bytes were skipped
@@ -535,32 +523,27 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
             Emit(reinterpret_cast<const char *>(&length), sizeof length,
                 sizeof length, handler);
       } else {
-        // Unformatted stream: nothing to do
+        // Terminate formatted variable length record
+        ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
       }
-    } else {
-      // Terminate formatted variable length record
-      ok = ok && Emit("\n", 1, 1, handler); // TODO: Windows CR+LF
     }
     if (IsAfterEndfile()) {
       return false;
     }
     CommitWrites();
+    impliedEndfile_ = true;
     ++currentRecordNumber;
-    if (access != Access::Direct) {
-      impliedEndfile_ = IsRecordFile();
-      if (IsAtEOF()) {
-        endfileRecordNumber.reset();
-      }
+    if (IsAtEOF()) {
+      endfileRecordNumber.reset();
     }
     return ok;
   }
 }
 
 void ExternalFileUnit::BackspaceRecord(IoErrorHandler &handler) {
-  if (access == Access::Direct || !IsRecordFile()) {
+  if (access != Access::Sequential) {
     handler.SignalError(IostatBackspaceNonSequential,
-        "BACKSPACE(UNIT=%d) on direct-access file or unformatted stream",
-        unitNumber());
+        "BACKSPACE(UNIT=%d) on non-sequential file", unitNumber());
   } else {
     if (IsAfterEndfile()) {
       // BACKSPACE after explicit ENDFILE
@@ -607,9 +590,9 @@ void ExternalFileUnit::FlushIfTerminal(IoErrorHandler &handler) {
 }
 
 void ExternalFileUnit::Endfile(IoErrorHandler &handler) {
-  if (access == Access::Direct) {
-    handler.SignalError(IostatEndfileDirect,
-        "ENDFILE(UNIT=%d) on direct-access file", unitNumber());
+  if (access != Access::Sequential) {
+    handler.SignalError(IostatEndfileNonSequential,
+        "ENDFILE(UNIT=%d) on non-sequential file", unitNumber());
   } else if (!mayWrite()) {
     handler.SignalError(IostatEndfileUnwritable,
         "ENDFILE(UNIT=%d) on read-only file", unitNumber());
@@ -617,11 +600,9 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) {
     // ENDFILE after ENDFILE
   } else {
     DoEndfile(handler);
-    if (access == Access::Sequential) {
-      // Explicit ENDFILE leaves position *after* the endfile record
-      RUNTIME_CHECK(handler, endfileRecordNumber.has_value());
-      currentRecordNumber = *endfileRecordNumber + 1;
-    }
+    // Explicit ENDFILE leaves position *after* the endfile record
+    RUNTIME_CHECK(handler, endfileRecordNumber.has_value());
+    currentRecordNumber = *endfileRecordNumber + 1;
   }
 }
 
@@ -630,18 +611,12 @@ void ExternalFileUnit::Rewind(IoErrorHandler &handler) {
     handler.SignalError(IostatRewindNonSequential,
         "REWIND(UNIT=%d) on non-sequential file", unitNumber());
   } else {
-    SetPosition(0, handler);
+    DoImpliedEndfile(handler);
+    SetPosition(0);
     currentRecordNumber = 1;
   }
 }
 
-void ExternalFileUnit::SetPosition(std::int64_t pos, IoErrorHandler &handler) {
-  DoImpliedEndfile(handler);
-  frameOffsetInFile_ = pos;
-  recordOffsetInFrame_ = 0;
-  BeginRecord();
-}
-
 void ExternalFileUnit::EndIoStatement() {
   io_.reset();
   u_.emplace<std::monostate>();
@@ -690,7 +665,7 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
   positionInRecord = sizeof header;
 }
 
-void ExternalFileUnit::BeginVariableFormattedInputRecord(
+void ExternalFileUnit::BeginSequentialVariableFormattedInputRecord(
     IoErrorHandler &handler) {
   if (this == defaultInput) {
     if (defaultOutput) {
@@ -715,7 +690,7 @@ void ExternalFileUnit::BeginVariableFormattedInputRecord(
       }
       break;
     }
-  } while (!SetVariableFormattedRecordLength());
+  } while (!SetSequentialVariableFormattedRecordLength());
 }
 
 void ExternalFileUnit::BackspaceFixedRecord(IoErrorHandler &handler) {
@@ -808,17 +783,14 @@ void ExternalFileUnit::BackspaceVariableFormattedRecord(
 void ExternalFileUnit::DoImpliedEndfile(IoErrorHandler &handler) {
   if (impliedEndfile_) {
     impliedEndfile_ = false;
-    if (access != Access::Direct && IsRecordFile() && mayPosition()) {
+    if (access == Access::Sequential && mayPosition()) {
       DoEndfile(handler);
     }
   }
 }
 
 void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) {
-  if (access == Access::Sequential) {
-    endfileRecordNumber = currentRecordNumber;
-  }
-  FlushOutput(handler);
+  endfileRecordNumber = currentRecordNumber;
   Truncate(frameOffsetInFile_ + recordOffsetInFrame_, handler);
   BeginRecord();
   impliedEndfile_ = false;

diff  --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index da6bc4b23d71..b7f4e271c01f 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -90,10 +90,10 @@ class ExternalFileUnit : public ConnectionState,
   void Endfile(IoErrorHandler &);
   void Rewind(IoErrorHandler &);
   void EndIoStatement();
-  void SetPosition(std::int64_t, IoErrorHandler &); // zero-based
-  std::int64_t InquirePos() const {
-    // 12.6.2.11 defines POS=1 as the beginning of file
-    return frameOffsetInFile_ + 1;
+  void SetPosition(std::int64_t pos) {
+    frameOffsetInFile_ = pos;
+    recordOffsetInFrame_ = 0;
+    BeginRecord();
   }
 
   ChildIo *GetChildIo() { return child_.get(); }
@@ -104,18 +104,18 @@ class ExternalFileUnit : public ConnectionState,
   static UnitMap &GetUnitMap();
   const char *FrameNextInput(IoErrorHandler &, std::size_t);
   void BeginSequentialVariableUnformattedInputRecord(IoErrorHandler &);
-  void BeginVariableFormattedInputRecord(IoErrorHandler &);
+  void BeginSequentialVariableFormattedInputRecord(IoErrorHandler &);
   void BackspaceFixedRecord(IoErrorHandler &);
   void BackspaceVariableUnformattedRecord(IoErrorHandler &);
   void BackspaceVariableFormattedRecord(IoErrorHandler &);
-  bool SetVariableFormattedRecordLength();
+  bool SetSequentialVariableFormattedRecordLength();
   void DoImpliedEndfile(IoErrorHandler &);
   void DoEndfile(IoErrorHandler &);
   void CommitWrites();
 
   int unitNumber_{-1};
   Direction direction_{Direction::Output};
-  bool impliedEndfile_{false}; // sequential/stream output has taken place
+  bool impliedEndfile_{false}; // seq. output has taken place
   bool beganReadingRecord_{false};
 
   Lock lock_;


        


More information about the flang-commits mailing list