[flang-commits] [flang] 36771bb - [flang][runtime] Correct emission & reading of unterminated final records

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Thu Apr 28 09:22:15 PDT 2022


Author: Peter Klausler
Date: 2022-04-28T09:22:07-07:00
New Revision: 36771bbad1b2588b66f9033074f1f2155065dffb

URL: https://github.com/llvm/llvm-project/commit/36771bbad1b2588b66f9033074f1f2155065dffb
DIFF: https://github.com/llvm/llvm-project/commit/36771bbad1b2588b66f9033074f1f2155065dffb.diff

LOG: [flang][runtime] Correct emission & reading of unterminated final records

When the last operation on a foramtted sequential or stream file (prior
to an implied or explicit ENDFILE) is a non-advancing WRITE, ensure
that any partial record data is emitted to the file without a line
terminator.  Further, when that last record is read with a non-advancing
READ, ensure that it won't raise an end-of-record condition after its
data, but instead will signal an end-of-file.

Differential Revision: https://reviews.llvm.org/D124546

Added: 
    

Modified: 
    flang/runtime/connection.h
    flang/runtime/io-stmt.cpp
    flang/runtime/unit.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index 09b84255b9226..a19c49f9aa048 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -54,6 +54,7 @@ struct ConnectionState : public ConnectionAttributes {
   void BeginRecord() {
     positionInRecord = 0;
     furthestPositionInRecord = 0;
+    unterminatedRecord = false;
   }
 
   std::optional<std::int64_t> EffectiveRecordLength() const {
@@ -85,6 +86,10 @@ struct ConnectionState : public ConnectionAttributes {
   // so that backspacing to the beginning of the repeated item doesn't require
   // repositioning the external storage medium when that's impossible.
   bool pinnedFrame{false};
+
+  // Set when the last record of a file is not properly terminated
+  // so that a non-advancing READ will not signal EOR.
+  bool unterminatedRecord{false};
 };
 
 // Utility class for capturing and restoring a position in an input stream.

diff  --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index ad0a4dc249ee3..8080263ff20d9 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -327,7 +327,6 @@ void ExternalIoStatementState<DIR>::CompleteOperation() {
       }
       unit().leftTabLimit = unit().furthestPositionInRecord;
     } else {
-      unit().leftTabLimit.reset();
       unit().AdvanceRecord(*this);
     }
     unit().FlushIfTerminal(*this);
@@ -673,7 +672,15 @@ bool IoStatementState::CheckForEndOfRecord() {
       if (connection.positionInRecord >= *length) {
         IoErrorHandler &handler{GetIoErrorHandler()};
         if (mutableModes().nonAdvancing) {
-          handler.SignalEor();
+          if (connection.access == Access::Stream &&
+              connection.unterminatedRecord) {
+            // Reading final unterminated record left by a
+            // non-advancing WRITE on a stream file prior to
+            // positioning or ENDFILE.
+            handler.SignalEnd();
+          } else {
+            handler.SignalEor();
+          }
         } else if (!connection.modes.pad) {
           handler.SignalError(IostatRecordReadOverrun);
         }

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index e7d0fd5f5959b..31c350f33d3b3 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -349,7 +349,7 @@ bool ExternalFileUnit::Receive(char *data, std::size_t bytes,
     return true;
   } else {
     handler.SignalEnd();
-    if (access == Access::Sequential) {
+    if (IsRecordFile() && access != Access::Direct) {
       endfileRecordNumber = currentRecordNumber;
     }
     return false;
@@ -385,7 +385,7 @@ const char *ExternalFileUnit::FrameNextInput(
       return Frame() + at;
     }
     handler.SignalEnd();
-    if (access == Access::Sequential) {
+    if (IsRecordFile() && access != Access::Direct) {
       endfileRecordNumber = currentRecordNumber;
     }
   }
@@ -544,6 +544,7 @@ bool ExternalFileUnit::AdvanceRecord(IoErrorHandler &handler) {
 #endif
       ok = ok && Emit(lineEnding, lineEndingBytes, 1, handler);
     }
+    leftTabLimit.reset();
     if (IsAfterEndfile()) {
       return false;
     }
@@ -620,7 +621,7 @@ void ExternalFileUnit::Endfile(IoErrorHandler &handler) {
     // ENDFILE after ENDFILE
   } else {
     DoEndfile(handler);
-    if (access == Access::Sequential) {
+    if (IsRecordFile() && access != Access::Direct) {
       // Explicit ENDFILE leaves position *after* the endfile record
       RUNTIME_CHECK(handler, endfileRecordNumber.has_value());
       currentRecordNumber = *endfileRecordNumber + 1;
@@ -716,6 +717,7 @@ void ExternalFileUnit::BeginVariableFormattedInputRecord(
       if (length > 0) {
         // final record w/o \n
         recordLength = length;
+        unterminatedRecord = true;
       } else {
         handler.SignalEnd();
       }
@@ -839,11 +841,17 @@ void ExternalFileUnit::DoImpliedEndfile(IoErrorHandler &handler) {
 }
 
 void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) {
-  if (IsRecordFile()) {
+  if (IsRecordFile() && access != Access::Direct) {
+    if (furthestPositionInRecord > 0) {
+      // Last write was non-advancing, so AdvanceRecord() was not called.
+      leftTabLimit.reset();
+      ++currentRecordNumber;
+    }
     endfileRecordNumber = currentRecordNumber;
   }
   FlushOutput(handler);
-  Truncate(frameOffsetInFile_ + recordOffsetInFrame_, handler);
+  Truncate(frameOffsetInFile_ + recordOffsetInFrame_ + furthestPositionInRecord,
+      handler);
   BeginRecord();
   impliedEndfile_ = false;
 }


        


More information about the flang-commits mailing list