[flang-commits] [flang] 7cf198f - [flang][runtime] Don't do partial data transfer on short character read with ADVANCE='NO', PAD='NO'
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Jul 17 10:04:27 PDT 2023
Author: Peter Klausler
Date: 2023-07-17T10:04:15-07:00
New Revision: 7cf198f7988bf94306d9a6cd26228b81f7c7ca7f
URL: https://github.com/llvm/llvm-project/commit/7cf198f7988bf94306d9a6cd26228b81f7c7ca7f
DIFF: https://github.com/llvm/llvm-project/commit/7cf198f7988bf94306d9a6cd26228b81f7c7ca7f.diff
LOG: [flang][runtime] Don't do partial data transfer on short character read with ADVANCE='NO', PAD='NO'
When a non-advancing formatted READ can't completely fill a CHARACTER
input item with data, and PAD='NO', don't modify the variable at all.
This matters when the error is recoverable.
Fixes https://github.com/llvm/llvm-project/issues/63772
Differential Revision: https://reviews.llvm.org/D155000
Added:
Modified:
flang/runtime/edit-input.cpp
flang/runtime/io-stmt.cpp
flang/runtime/io-stmt.h
flang/unittests/Runtime/ExternalIOTest.cpp
Removed:
################################################################################
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 7287d2e99979d9..98627c9dd82750 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -719,7 +719,7 @@ bool EditCharacterInput(
}
// When the field is wider than the variable, we drop the leading
// characters. When the variable is wider than the field, there can be
- // trailing padding.
+ // trailing padding or an EOR condition.
const char *input{nullptr};
std::size_t ready{0};
// Skip leading bytes.
@@ -729,11 +729,18 @@ bool EditCharacterInput(
while (remaining > 0) {
if (ready == 0) {
ready = io.GetNextInputBytes(input);
- if (ready == 0) {
- if (io.CheckForEndOfRecord()) {
- std::fill_n(x, length, ' '); // PAD='YES'
+ if (ready == 0 || (ready < remaining && edit.modes.nonAdvancing)) {
+ if (io.CheckForEndOfRecord(ready)) {
+ if (ready == 0) {
+ // PAD='YES' and no more data
+ std::fill_n(x, length, ' ');
+ return !io.GetIoErrorHandler().InError();
+ } else {
+ // Do partial read(s) then pad on last iteration
+ }
+ } else {
+ return !io.GetIoErrorHandler().InError();
}
- return !io.GetIoErrorHandler().InError();
}
}
std::size_t chunk;
diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 6935f1fdfa22cb..d18f81b93faf24 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -589,7 +589,7 @@ std::optional<char32_t> IoStatementState::NextInField(
GotChar(byteCount);
return next;
}
- if (CheckForEndOfRecord()) { // do padding
+ if (CheckForEndOfRecord(0)) { // do padding
--*remaining;
return std::optional<char32_t>{' '};
}
@@ -597,11 +597,13 @@ std::optional<char32_t> IoStatementState::NextInField(
return std::nullopt;
}
-bool IoStatementState::CheckForEndOfRecord() {
+bool IoStatementState::CheckForEndOfRecord(std::size_t afterReading) {
const ConnectionState &connection{GetConnectionState()};
if (!connection.IsAtEOF()) {
if (auto length{connection.EffectiveRecordLength()}) {
- if (connection.positionInRecord >= *length) {
+ if (connection.positionInRecord +
+ static_cast<std::int64_t>(afterReading) >=
+ *length) {
IoErrorHandler &handler{GetIoErrorHandler()};
const auto &modes{mutableModes()};
if (modes.nonAdvancing) {
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index c1fdc29f8c255e..33653e69ad4ed6 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -169,7 +169,7 @@ class IoStatementState {
// Detect and signal any end-of-record condition after input.
// Returns true if at EOR and remaining input should be padded with blanks.
- bool CheckForEndOfRecord();
+ bool CheckForEndOfRecord(std::size_t afterReading);
// Skips spaces, advances records, and ignores NAMELIST comments
std::optional<char32_t> GetNextNonBlank(std::size_t &byteCount) {
diff --git a/flang/unittests/Runtime/ExternalIOTest.cpp b/flang/unittests/Runtime/ExternalIOTest.cpp
index 389abf1d0404a7..bc1fb7faa43149 100644
--- a/flang/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang/unittests/Runtime/ExternalIOTest.cpp
@@ -525,35 +525,64 @@ TEST(ExternalIOTests, TestNonAvancingInput) {
struct TestItems {
std::string item;
int expectedIoStat;
- std::string expectedItemValue;
+ std::string expectedItemValue[2];
};
// 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 "},
+ {std::string(4, '+'), IostatOk, "ABCD", "ABCD"},
+ {std::string(4, '+'), IostatOk, "EFGH", "EFGH"},
+ {std::string(4, '+'), IostatEor, "++++", " "},
+ {std::string(2, '+'), IostatOk, "IJ", "IJ"},
+ {std::string(8, '+'), IostatEor, "++++++++", "KLMNOP "},
+ {std::string(10, '+'), IostatEor, "++++++++++", "QRSTUVWX "},
};
+ // Test with PAD='NO'
int j{0};
for (auto &inputItem : inputItems) {
- // READ(UNIT=unit, FMT=fmt, ADVANCE='NO', IOSTAT=iostat) inputItem
+ // READ(UNIT=unit, FMT=fmt, ADVANCE='NO', PAD='NO', IOSTAT=iostat) inputItem
io = IONAME(BeginExternalFormattedInput)(
fmt.data(), fmt.length(), nullptr, unit, __FILE__, __LINE__);
IONAME(EnableHandlers)(io, true, false, false, false, false);
ASSERT_TRUE(IONAME(SetAdvance)(io, "NO", 2)) << "SetAdvance(NO)" << j;
+ ASSERT_TRUE(IONAME(SetPad)(io, "NO", 2)) << "SetPad(NO)" << j;
bool result{
IONAME(InputAscii)(io, inputItem.item.data(), inputItem.item.length())};
ASSERT_EQ(result, inputItem.expectedIoStat == IostatOk)
<< "InputAscii() " << j;
ASSERT_EQ(IONAME(EndIoStatement)(io), inputItem.expectedIoStat)
<< "EndIoStatement() for Read " << j;
- ASSERT_EQ(inputItem.item, inputItem.expectedItemValue)
+ ASSERT_EQ(inputItem.item, inputItem.expectedItemValue[0])
+ << "Input-item value after non advancing read " << j;
+ j++;
+ }
+
+ // REWIND(UNIT=unit)
+ io = IONAME(BeginRewind)(unit, __FILE__, __LINE__);
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+ << "EndIoStatement() for Rewind";
+
+ // Test again with PAD='YES'
+ j = 0;
+ for (auto &inputItem : inputItems) {
+ // READ(UNIT=unit, FMT=fmt, ADVANCE='NO', PAD='YES', IOSTAT=iostat)
+ // inputItem
+ io = IONAME(BeginExternalFormattedInput)(
+ fmt.data(), fmt.length(), nullptr, unit, __FILE__, __LINE__);
+ IONAME(EnableHandlers)(io, true, false, false, false, false);
+ ASSERT_TRUE(IONAME(SetAdvance)(io, "NO", 2)) << "SetAdvance(NO)" << j;
+ ASSERT_TRUE(IONAME(SetPad)(io, "YES", 3)) << "SetPad(YES)" << j;
+ bool result{
+ IONAME(InputAscii)(io, inputItem.item.data(), inputItem.item.length())};
+ ASSERT_EQ(result, inputItem.expectedIoStat == IostatOk)
+ << "InputAscii() " << j;
+ ASSERT_EQ(IONAME(EndIoStatement)(io), inputItem.expectedIoStat)
+ << "EndIoStatement() for Read " << j;
+ ASSERT_EQ(inputItem.item, inputItem.expectedItemValue[1])
<< "Input-item value after non advancing read " << j;
j++;
}
+
// CLOSE(UNIT=unit)
io = IONAME(BeginClose)(unit, __FILE__, __LINE__);
ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
More information about the flang-commits
mailing list