[flang-commits] [flang] 05b4e49 - [flang] Signal EOR in non advancing IO and move to next record

Jean Perier via flang-commits flang-commits at lists.llvm.org
Fri Sep 10 04:09:11 PDT 2021


Author: Jean Perier
Date: 2021-09-10T13:08:02+02:00
New Revision: 05b4e49a17f5e997c0ccf4086dc0d2b8cec7e263

URL: https://github.com/llvm/llvm-project/commit/05b4e49a17f5e997c0ccf4086dc0d2b8cec7e263
DIFF: https://github.com/llvm/llvm-project/commit/05b4e49a17f5e997c0ccf4086dc0d2b8cec7e263.diff

LOG: [flang] Signal EOR in non advancing IO and move to next record

When an end of record is met in non advancing IO:
- Set IOSTAT if present according to 12.11.4 (5).
- Position the file to the next record (12.11.4 (4)).

The previous code was only signaling EOR for fixed record length IO.
Reading at 12.11.4, I do not find the rational for this condition, so I
removed it.
It also does not seem the presence of padding should prevent
the EOR signaling.

The positionning to the next record was block when EOR is signaling
in FinishReadingRecord because ErrorHandler.isError() is true in this
case.
EOR in input is not an error, but I am not confident to modify
ErrorHandler.isError() to cover that. However, In FinishReadingRecord,
the code should not bail if the error is simply an end of record.

I did not check the SIZE requirements here because GetSize runtime is
not yet implemented.

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

Added: 
    

Modified: 
    flang/runtime/io-stmt.cpp
    flang/runtime/unit.cpp
    flang/unittests/Runtime/ExternalIOTest.cpp

Removed: 
    


################################################################################
diff  --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 0f64d76af5667..94de61c509530 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -272,7 +272,7 @@ ExternalIoStatementState<DIR>::ExternalIoStatementState(
 template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
   if constexpr (DIR == Direction::Input) {
     BeginReadingRecord(); // in case there were no I/O items
-    if (!mutableModes().nonAdvancing) {
+    if (!mutableModes().nonAdvancing || GetIoStat() == IostatEor) {
       FinishReadingRecord();
     }
   } else {
@@ -559,19 +559,18 @@ std::optional<char32_t> IoStatementState::NextInField(
       return next;
     }
     const ConnectionState &connection{GetConnectionState()};
-    if (!connection.IsAtEOF() && connection.isFixedRecordLength &&
-        connection.recordLength &&
+    if (!connection.IsAtEOF() && connection.recordLength &&
         connection.positionInRecord >= *connection.recordLength) {
-      if (connection.modes.pad) { // PAD='YES'
-        --*remaining;
-        return std::optional<char32_t>{' '};
-      }
       IoErrorHandler &handler{GetIoErrorHandler()};
       if (mutableModes().nonAdvancing) {
         handler.SignalEor();
-      } else {
+      } else if (connection.isFixedRecordLength && !connection.modes.pad) {
         handler.SignalError(IostatRecordReadOverrun);
       }
+      if (connection.modes.pad) { // PAD='YES'
+        --*remaining;
+        return std::optional<char32_t>{' '};
+      }
     }
   }
   return std::nullopt;

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 33eda31fbb45c..b823789ea0887 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -402,7 +402,7 @@ bool ExternalFileUnit::BeginReadingRecord(IoErrorHandler &handler) {
 void ExternalFileUnit::FinishReadingRecord(IoErrorHandler &handler) {
   RUNTIME_CHECK(handler, direction_ == Direction::Input && beganReadingRecord_);
   beganReadingRecord_ = false;
-  if (handler.InError()) {
+  if (handler.InError() && handler.GetIoStat() != IostatEor) {
     // avoid bogus crashes in END/ERR circumstances
   } else if (access == Access::Sequential) {
     RUNTIME_CHECK(handler, recordLength.has_value());

diff  --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp
index b75a7fe7d027b..0b2accf43496e 100644
--- a/flang/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang/unittests/Runtime/ExternalIOTest.cpp
@@ -17,6 +17,7 @@
 #include "flang/Runtime/stop.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cstring>
+#include <string_view>
 
 using namespace Fortran::runtime::io;
 
@@ -446,3 +447,70 @@ TEST(ExternalIOTests, TestSequentialVariableFormatted) {
   ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
       << "EndIoStatement() for Close";
 }
+
+TEST(ExternalIOTests, TestNonAvancingInput) {
+  // OPEN(NEWUNIT=unit,ACCESS='SEQUENTIAL',ACTION='READWRITE',&
+  //   FORM='FORMATTED',STATUS='SCRATCH')
+  auto *io{IONAME(BeginOpenNewUnit)(__FILE__, __LINE__)};
+  ASSERT_TRUE(IONAME(SetAccess)(io, "SEQUENTIAL", 10))
+      << "SetAccess(SEQUENTIAL)";
+  ASSERT_TRUE(IONAME(SetAction)(io, "READWRITE", 9)) << "SetAction(READWRITE)";
+  ASSERT_TRUE(IONAME(SetForm)(io, "FORMATTED", 9)) << "SetForm(FORMATTED)";
+  ASSERT_TRUE(IONAME(SetStatus)(io, "SCRATCH", 7)) << "SetStatus(SCRATCH)";
+
+  int unit{-1};
+  ASSERT_TRUE(IONAME(GetNewUnit)(io, unit)) << "GetNewUnit()";
+  ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+      << "EndIoStatement() for OpenNewUnit";
+
+  // Write the file to be used for the input test.
+  static constexpr std::string_view records[] = {
+      "ABCDEFGH", "IJKLMNOP", "QRSTUVWX"};
+  static constexpr std::string_view fmt{"(A)"};
+  for (const auto &record : records) {
+    // WRITE(UNIT=unit,FMT=fmt) record
+    io = IONAME(BeginExternalFormattedOutput)(
+        fmt.data(), fmt.length(), unit, __FILE__, __LINE__);
+    ASSERT_TRUE(IONAME(OutputAscii)(io, record.data(), record.length()))
+        << "OutputAscii()";
+    ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+        << "EndIoStatement() for OutputAscii";
+  }
+
+  // REWIND(UNIT=unit)
+  io = IONAME(BeginRewind)(unit, __FILE__, __LINE__);
+  ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+      << "EndIoStatement() for Rewind";
+
+  struct TestItems {
+    std::string item;
+    int expectedIoStat;
+    std::string expectedItemValue;
+  };
+  // Actual non advancing input IO test
+  TestItems inputItems[]{
+      {std::string(4, '+'), IostatOk, "ABCD"},
+      {std::string(4, '+'), IostatOk, "EFGH"},
+      {std::string(4, '+'), IostatEor, "    "},
+      {std::string(2, '+'), IostatOk, "IJ"},
+      {std::string(8, '+'), IostatEor, "KLMNOP  "},
+      {std::string(10, '+'), IostatEor, "QRSTUVWX  "},
+  };
+
+  int j{0};
+  for (auto &inputItem : inputItems) {
+    // READ(UNIT=unit, FMT=fmt, ADVANCE='NO', IOSTAT=iostat) inputItem
+    io = IONAME(BeginExternalFormattedInput)(
+        fmt.data(), fmt.length(), unit, __FILE__, __LINE__);
+    IONAME(EnableHandlers)(io, true, false, false, false, false);
+    ASSERT_TRUE(IONAME(SetAdvance)(io, "NO", 2)) << "SetAdvance(NO)" << j;
+    ASSERT_TRUE(
+        IONAME(InputAscii)(io, inputItem.item.data(), inputItem.item.length()))
+        << "InputAscii() " << j;
+    ASSERT_EQ(IONAME(EndIoStatement)(io), inputItem.expectedIoStat)
+        << "EndIoStatement() for Read " << j;
+    ASSERT_EQ(inputItem.item, inputItem.expectedItemValue)
+        << "Input-item value after non advancing read " << j;
+    j++;
+  }
+}


        


More information about the flang-commits mailing list