[flang-commits] [flang] 2e65c8e - [flang] Allow write after non advancing read in IO runtime

Jean Perier via flang-commits flang-commits at lists.llvm.org
Tue Nov 16 05:54:25 PST 2021


Author: Jean Perier
Date: 2021-11-16T14:53:39+01:00
New Revision: 2e65c8e8db1887a39c9140b75a9f5bb892ddd93f

URL: https://github.com/llvm/llvm-project/commit/2e65c8e8db1887a39c9140b75a9f5bb892ddd93f
DIFF: https://github.com/llvm/llvm-project/commit/2e65c8e8db1887a39c9140b75a9f5bb892ddd93f.diff

LOG: [flang] Allow write after non advancing read in IO runtime

1. To avoid overwriting the part of the record read in the non advancing read,
the furtherPositionInRecord field must be set to the max of the
furtherPositionInRecord and the positionInRecord at the beginning of the
IO write.

2. To allow any further read to succeed after the write, the unit
beganReadingRecord_ must be set to false when resetting the recordLength
during the write, otherwise, recordLength will not be computed in further
read and an assert is hit (at unit.cpp(398)).

The added unit test exercises both of these scenarios.

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

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 afb0935ac40ad..5d5714ac2b69d 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -264,7 +264,16 @@ template <Direction DIR>
 ExternalIoStatementState<DIR>::ExternalIoStatementState(
     ExternalFileUnit &unit, const char *sourceFile, int sourceLine)
     : ExternalIoStatementBase{unit, sourceFile, sourceLine}, mutableModes_{
-                                                                 unit.modes} {}
+                                                                 unit.modes} {
+  if constexpr (DIR == Direction::Output) {
+    // 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.
+    unit.furthestPositionInRecord =
+        std::max(unit.furthestPositionInRecord, unit.positionInRecord);
+  }
+}
 
 template <Direction DIR> int ExternalIoStatementState<DIR>::EndIoStatement() {
   if constexpr (DIR == Direction::Input) {

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index 50b70c001db30..2b87d4b3ee810 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -261,9 +261,10 @@ bool ExternalFileUnit::Emit(const char *data, std::size_t bytes,
   if (recordLength) {
     // It is possible for recordLength to have a value now for a
     // variable-length output record if the previous operation
-    // was a BACKSPACE.
+    // was a BACKSPACE or non advancing input statement.
     if (!isFixedRecordLength) {
       recordLength.reset();
+      beganReadingRecord_ = false;
     } else if (furthestAfter > *recordLength) {
       handler.SignalError(IostatRecordWriteOverrun,
           "Attempt to write %zd bytes to position %jd in a fixed-size record "

diff  --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp
index 13347a7730af8..070950c6132bc 100644
--- a/flang/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang/unittests/Runtime/ExternalIOTest.cpp
@@ -537,3 +537,98 @@ TEST(ExternalIOTests, TestNonAvancingInput) {
     j++;
   }
 }
+
+TEST(ExternalIOTests, TestWriteAfterNonAvancingInput) {
+  // 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[] = {"ABCDEFGHIJKLMNOPQRST"};
+  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"},
+  };
+
+  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++;
+  }
+
+  // WRITE(UNIT=unit, FMT=fmt, IOSTAT=iostat) outputItem.
+  static constexpr std::string_view outputItem{"XYZ"};
+  // WRITE(UNIT=unit,FMT=fmt) record
+  io = IONAME(BeginExternalFormattedOutput)(
+      fmt.data(), fmt.length(), unit, __FILE__, __LINE__);
+  ASSERT_TRUE(IONAME(OutputAscii)(io, outputItem.data(), outputItem.length()))
+      << "OutputAscii()";
+  ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+      << "EndIoStatement() for OutputAscii";
+
+  // Verify that the output was written in the record read in non avdancing
+  // mode, after the read part, and that the end was truncated.
+
+  // REWIND(UNIT=unit)
+  io = IONAME(BeginRewind)(unit, __FILE__, __LINE__);
+  ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+      << "EndIoStatement() for Rewind";
+
+  std::string resultRecord(20, '+');
+  std::string expectedRecord{"ABCDEFGHXYZ         "};
+  // READ(UNIT=unit, FMT=fmt, IOSTAT=iostat) result
+  io = IONAME(BeginExternalFormattedInput)(
+      fmt.data(), fmt.length(), unit, __FILE__, __LINE__);
+  IONAME(EnableHandlers)(io, true, false, false, false, false);
+  ASSERT_TRUE(
+      IONAME(InputAscii)(io, resultRecord.data(), resultRecord.length()))
+      << "InputAscii() ";
+  ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+      << "EndIoStatement() for Read ";
+
+  ASSERT_EQ(resultRecord, expectedRecord)
+      << "Record after non advancing read followed by wrote";
+}


        


More information about the flang-commits mailing list