diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -267,7 +267,16 @@
ExternalIoStatementState
::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 int ExternalIoStatementState::EndIoStatement() {
if constexpr (DIR == Direction::Input) {
diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -261,9 +261,10 @@
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
--- a/flang/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang/unittests/Runtime/ExternalIOTest.cpp
@@ -537,3 +537,98 @@
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";
+}