[flang-commits] [flang] [flang][runtime] Fix fixed-width field internal wide character input (PR #74683)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Wed Dec 6 16:36:08 PST 2023
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/74683
There was some confusion about units (bytes vs characters) in the handling of the amount of input remaining in fixed-width formatted input fields. Clarify that any variable or parameter counting "remaining" space in a field in the I/O runtime is always in units of bytes, and make it so where it wasn't.
Fixes the bug(s) in llvm-test-suite/Fortran/gfortran/regression/char4_iunit_2.f03, although the test still won't pass due to its dependence on gfortran's list-directed output spacing.
>From f71e7e0b024dec0aa6660d342700f46b2238f8d7 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Wed, 6 Dec 2023 16:31:18 -0800
Subject: [PATCH] [flang][runtime] Fix fixed-width field internal wide
character input
There was some confusion about units (bytes vs characters) in the
handling of the amount of input remaining in fixed-width formatted
input fields. Clarify that any variable or parameter counting "remaining"
space in a field in the I/O runtime is always in units of bytes, and
make it so where it wasn't.
Fixes the bug(s) in llvm-test-suite/Fortran/gfortran/regression/char4_iunit_2.f03,
although the test still won't pass due to its dependence on gfortran's
list-directed output spacing.
---
flang/runtime/edit-input.cpp | 19 ++++++++++---------
flang/runtime/io-stmt.h | 14 +++++++++++---
2 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/flang/runtime/edit-input.cpp b/flang/runtime/edit-input.cpp
index 4e8c9aa868a69..9dcca5bea6d93 100644
--- a/flang/runtime/edit-input.cpp
+++ b/flang/runtime/edit-input.cpp
@@ -915,18 +915,22 @@ bool EditCharacterInput(
return false;
}
const ConnectionState &connection{io.GetConnectionState()};
- std::size_t remaining{length};
+ int unitBytesPerChar{std::max<int>(connection.internalIoCharKind, 1)};
+ std::size_t remaining{length * unitBytesPerChar};
+ // Skip leading characters.
+ // Their bytes don't count towards INQUIRE(IOLENGTH=).
+ std::size_t skip{0};
if (edit.width && *edit.width > 0) {
- remaining = *edit.width;
+ remaining = *edit.width * unitBytesPerChar;
+ if (static_cast<std::size_t>(*edit.width) > length) {
+ skip = *edit.width - length;
+ }
}
// 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 or an EOR condition.
const char *input{nullptr};
std::size_t ready{0};
- // Skip leading bytes.
- // These bytes don't count towards INQUIRE(IOLENGTH=).
- std::size_t skip{remaining > length ? remaining - length : 0};
// Transfer payload bytes; these do count.
while (remaining > 0) {
if (ready == 0) {
@@ -958,7 +962,6 @@ bool EditCharacterInput(
// error recovery: skip bad encoding
chunk = 1;
}
- --remaining;
} else if (connection.internalIoCharKind > 1) {
// Reading from non-default character internal unit
chunk = connection.internalIoCharKind;
@@ -970,7 +973,6 @@ bool EditCharacterInput(
*x++ = buffer;
--length;
}
- --remaining;
} else if constexpr (sizeof *x > 1) {
// Read single byte with expansion into multi-byte CHARACTER
chunk = 1;
@@ -980,7 +982,6 @@ bool EditCharacterInput(
*x++ = static_cast<unsigned char>(*input);
--length;
}
- --remaining;
} else { // single bytes -> default CHARACTER
if (skipping) {
chunk = std::min<std::size_t>(skip, ready);
@@ -991,9 +992,9 @@ bool EditCharacterInput(
x += chunk;
length -= chunk;
}
- remaining -= chunk;
}
input += chunk;
+ remaining -= chunk;
if (!skipping) {
io.GotChar(chunk);
}
diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h
index d4ceb83265246..91169f6c6e323 100644
--- a/flang/runtime/io-stmt.h
+++ b/flang/runtime/io-stmt.h
@@ -92,8 +92,8 @@ class IoStatementState {
std::size_t GetNextInputBytes(const char *&);
bool AdvanceRecord(int = 1);
void BackspaceRecord();
- void HandleRelativePosition(std::int64_t);
- void HandleAbsolutePosition(std::int64_t); // for r* in list I/O
+ void HandleRelativePosition(std::int64_t byteOffset);
+ void HandleAbsolutePosition(std::int64_t byteOffset); // for r* in list I/O
std::optional<DataEdit> GetNextDataEdit(int maxRepeat = 1);
ExternalFileUnit *GetExternalFileUnit() const; // null if internal unit
bool BeginReadingRecord();
@@ -124,7 +124,11 @@ class IoStatementState {
// Vacant after the end of the current record
std::optional<char32_t> GetCurrentChar(std::size_t &byteCount);
- // For fixed-width fields, return the number of remaining characters.
+ // The "remaining" arguments to CueUpInput(), SkipSpaces(), & NextInField()
+ // are always in units of bytes, not characters; the distinction matters
+ // for internal input from CHARACTER(KIND=2 and 4).
+
+ // For fixed-width fields, return the number of remaining bytes.
// Skip over leading blanks.
std::optional<int> CueUpInput(const DataEdit &edit) {
std::optional<int> remaining;
@@ -134,6 +138,10 @@ class IoStatementState {
} else {
if (edit.width.value_or(0) > 0) {
remaining = *edit.width;
+ if (int bytesPerChar{GetConnectionState().internalIoCharKind};
+ bytesPerChar > 1) {
+ *remaining *= bytesPerChar;
+ }
}
SkipSpaces(remaining);
}
More information about the flang-commits
mailing list