diff --git a/flang/runtime/connection.h b/flang/runtime/connection.h index acda51124e0d4..70c20e17fd01a 100644 --- a/flang/runtime/connection.h +++ b/flang/runtime/connection.h @@ -74,7 +74,7 @@ struct ConnectionState : public ConnectionAttributes { std::int64_t currentRecordNumber{1}; // 1 is first - // positionInRecord is the 0-based bytes offset in the current recurd + // positionInRecord is the 0-based bytes offset in the current record // to/from which the next data transfer will occur. It can be past // furthestPositionInRecord if moved by an X or T or TR control edit // descriptor. diff --git a/flang/runtime/descriptor-io.cpp b/flang/runtime/descriptor-io.cpp index d34ac68c8a533..c6b57bf5f088d 100644 --- a/flang/runtime/descriptor-io.cpp +++ b/flang/runtime/descriptor-io.cpp @@ -50,6 +50,13 @@ std::optional DefinedFormattedIo(IoStatementState &io, int unit{external->unitNumber()}; int ioStat{IostatOk}; char ioMsg[100]; + std::optional startPos; + if (edit.descriptor == DataEdit::DefinedDerivedType && + special.which() == typeInfo::SpecialBinding::Which::ReadFormatted) { + // DT is an edit descriptor so everything that the child + // I/O subroutine reads counts towards READ(SIZE=). + startPos = io.InquirePos(); + } if (special.IsArgDescriptor(0)) { auto *p{special.GetProc()}; @@ -69,6 +76,9 @@ std::optional DefinedFormattedIo(IoStatementState &io, RUNTIME_CHECK(handler, external == closing); external->DestroyClosed(); } + if (startPos) { + io.GotChar(io.InquirePos() - *startPos); + } return handler.GetIoStat() == IostatOk; } else { // There's a user-defined I/O subroutine, but there's a FORMAT present and diff --git a/flang/runtime/internal-unit.cpp b/flang/runtime/internal-unit.cpp index a38db49a83ed6..aa7130f3a6a53 100644 --- a/flang/runtime/internal-unit.cpp +++ b/flang/runtime/internal-unit.cpp @@ -157,6 +157,12 @@ void InternalDescriptorUnit::BackspaceRecord(IoErrorHandler &handler) { BeginRecord(); } +template +std::int64_t InternalDescriptorUnit::InquirePos() { + return (currentRecordNumber - 1) * recordLength.value_or(0) + + positionInRecord + 1; +} + template class InternalDescriptorUnit; template class InternalDescriptorUnit; } // namespace Fortran::runtime::io diff --git a/flang/runtime/internal-unit.h b/flang/runtime/internal-unit.h index 06e54dee10f6b..f0c50aac98878 100644 --- a/flang/runtime/internal-unit.h +++ b/flang/runtime/internal-unit.h @@ -34,6 +34,7 @@ template class InternalDescriptorUnit : public ConnectionState { std::size_t GetNextInputBytes(const char *&, IoErrorHandler &); bool AdvanceRecord(IoErrorHandler &); void BackspaceRecord(IoErrorHandler &); + std::int64_t InquirePos(); private: Descriptor &descriptor() { return staticDescriptor_.descriptor(); } diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp index 8e75ca5f68824..9467822d8e410 100644 --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -70,6 +70,8 @@ bool IoStatementBase::Inquire(InquiryKeywordHash, std::int64_t &) { return false; } +std::int64_t IoStatementBase::InquirePos() { return 0; } + void IoStatementBase::BadInquiryKeywordHashCrash(InquiryKeywordHash inquiry) { char buffer[16]; const char *decode{InquiryKeywordHashDecode(buffer, sizeof buffer, inquiry)}; @@ -137,6 +139,11 @@ void InternalIoStatementState::HandleRelativePosition(std::int64_t n) { return unit_.HandleRelativePosition(n); } +template +std::int64_t InternalIoStatementState::InquirePos() { + return unit_.InquirePos(); +} + template InternalFormattedIoStatementState::InternalFormattedIoStatementState( Buffer buffer, std::size_t length, const CharType *format, @@ -206,6 +213,10 @@ void ExternalIoStatementBase::SetAsynchronous() { asynchronousID_ = unit().GetAsynchronousId(*this); } +std::int64_t ExternalIoStatementBase::InquirePos() { + return unit_.InquirePos(); +} + void OpenStatementState::set_path(const char *path, std::size_t length) { pathLength_ = TrimTrailingSpaces(path, length); path_ = SaveDefaultCharacter(path, pathLength_, *this); @@ -635,6 +646,10 @@ bool IoStatementState::Inquire(InquiryKeywordHash inquiry, std::int64_t &n) { [&](auto &x) { return x.get().Inquire(inquiry, n); }, u_); } +std::int64_t IoStatementState::InquirePos() { + return common::visit([&](auto &x) { return x.get().InquirePos(); }, u_); +} + void IoStatementState::GotChar(int n) { if (auto *formattedIn{ get_if>()}) { @@ -823,10 +838,6 @@ ExternalFileUnit *ChildIoStatementState::GetExternalFileUnit() const { return child_.parent().GetExternalFileUnit(); } -template void ChildIoStatementState::CompleteOperation() { - IoStatementBase::CompleteOperation(); -} - template int ChildIoStatementState::EndIoStatement() { CompleteOperation(); auto result{IoStatementBase::EndIoStatement()}; diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h index a4aa908378215..c1fdc29f8c255 100644 --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -102,6 +102,7 @@ class IoStatementState { bool Inquire(InquiryKeywordHash, bool &); bool Inquire(InquiryKeywordHash, std::int64_t, bool &); // PENDING= bool Inquire(InquiryKeywordHash, std::int64_t &); + std::int64_t InquirePos(); void GotChar(signed int = 1); // for READ(SIZE=); can be <0 MutableModes &mutableModes(); @@ -262,6 +263,7 @@ class IoStatementBase : public IoErrorHandler { bool Inquire(InquiryKeywordHash, bool &); bool Inquire(InquiryKeywordHash, std::int64_t, bool &); bool Inquire(InquiryKeywordHash, std::int64_t &); + std::int64_t InquirePos(); void BadInquiryKeywordHashCrash(InquiryKeywordHash); @@ -343,6 +345,7 @@ class InternalIoStatementState : public IoStatementBase, MutableModes &mutableModes() { return unit_.modes; } void HandleRelativePosition(std::int64_t); void HandleAbsolutePosition(std::int64_t); + std::int64_t InquirePos(); protected: bool free_{true}; @@ -406,6 +409,7 @@ class ExternalIoStatementBase : public IoStatementBase { int EndIoStatement(); ExternalFileUnit *GetExternalFileUnit() const { return &unit_; } void SetAsynchronous(); + std::int64_t InquirePos(); private: ExternalFileUnit &unit_; @@ -483,7 +487,6 @@ class ChildIoStatementState : public IoStatementBase, MutableModes &mutableModes(); ConnectionState &GetConnectionState(); ExternalFileUnit *GetExternalFileUnit() const; - void CompleteOperation(); int EndIoStatement(); bool Emit(const char *, std::size_t bytes, std::size_t elementBytes = 0); std::size_t GetNextInputBytes(const char *&);