[llvm] [flang][runtime] OPEN(existingUnit,POSITION=) (PR #153688)

Peter Klausler via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 15 17:47:48 PDT 2025


https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/153688

>From ae52c13d5ee393fc031314689ec5df0435691c3e Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 14 Aug 2025 13:43:17 -0700
Subject: [PATCH] [flang][runtime] OPEN(existingUnit,POSITION=)

Ensure that when a connected unit is reopened with POSITION='REWIND'
or 'APPEND', and a STATUS='OLD' or unspecified, that it is actually
repositioned as requested.

Fixes https://github.com/llvm/llvm-project/issues/153426.
---
 flang-rt/include/flang-rt/runtime/file.h |  4 ++--
 flang-rt/lib/runtime/external-unit.cpp   | 14 +++++++-------
 flang-rt/lib/runtime/file.cpp            | 24 ++++++++++++++++--------
 flang-rt/lib/runtime/unit.h              |  4 ++++
 4 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/file.h b/flang-rt/include/flang-rt/runtime/file.h
index 3bba29722b3b8..6e35fe89b5341 100644
--- a/flang-rt/include/flang-rt/runtime/file.h
+++ b/flang-rt/include/flang-rt/runtime/file.h
@@ -68,7 +68,7 @@ class OpenFile {
   void WaitAll(IoErrorHandler &);
 
   // INQUIRE(POSITION=)
-  Position InquirePosition() const;
+  Position InquirePosition(FileOffset offset) const;
 
 private:
   struct Pending {
@@ -80,7 +80,7 @@ class OpenFile {
   void CheckOpen(const Terminator &);
   bool Seek(FileOffset, IoErrorHandler &);
   bool RawSeek(FileOffset);
-  bool RawSeekToEnd();
+  bool SeekToEnd(IoErrorHandler &);
   int PendingResult(const Terminator &, int);
   void SetPosition(FileOffset pos) {
     position_ = pos;
diff --git a/flang-rt/lib/runtime/external-unit.cpp b/flang-rt/lib/runtime/external-unit.cpp
index b8004d6315994..42441e59d9bb6 100644
--- a/flang-rt/lib/runtime/external-unit.cpp
+++ b/flang-rt/lib/runtime/external-unit.cpp
@@ -57,7 +57,7 @@ ExternalFileUnit *ExternalFileUnit::LookUpOrCreate(
 }
 
 ExternalFileUnit *ExternalFileUnit::LookUpOrCreateAnonymous(int unit,
-    Direction dir, Fortran::common::optional<bool> isUnformatted,
+    Direction dir, common::optional<bool> isUnformatted,
     IoErrorHandler &handler) {
   // Make sure that the returned anonymous unit has been opened,
   // not just created in the unitMap.
@@ -109,8 +109,8 @@ ExternalFileUnit &ExternalFileUnit::NewUnit(
   return unit;
 }
 
-bool ExternalFileUnit::OpenUnit(Fortran::common::optional<OpenStatus> status,
-    Fortran::common::optional<Action> action, Position position,
+bool ExternalFileUnit::OpenUnit(common::optional<OpenStatus> status,
+    common::optional<Action> action, Position position,
     OwningPtr<char> &&newPath, std::size_t newPathLength, Convert convert,
     IoErrorHandler &handler) {
   if (convert == Convert::Unknown) {
@@ -131,6 +131,7 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional<OpenStatus> status,
     if (!newPath.get() || isSamePath) {
       // OPEN of existing unit, STATUS='OLD' or unspecified, not new FILE=
       newPath.reset();
+      Open(status.value_or(OpenStatus::Old), action, position, handler);
       return impliedClose;
     }
     // Otherwise, OPEN on open unit with new FILE= implies CLOSE
@@ -194,10 +195,9 @@ bool ExternalFileUnit::OpenUnit(Fortran::common::optional<OpenStatus> status,
   return impliedClose;
 }
 
-bool ExternalFileUnit::OpenAnonymousUnit(
-    Fortran::common::optional<OpenStatus> status,
-    Fortran::common::optional<Action> action, Position position,
-    Convert convert, IoErrorHandler &handler) {
+bool ExternalFileUnit::OpenAnonymousUnit(common::optional<OpenStatus> status,
+    common::optional<Action> action, Position position, Convert convert,
+    IoErrorHandler &handler) {
   // I/O to an unconnected unit reads/creates a local file, e.g. fort.7
   std::size_t pathMaxLen{32};
   auto path{SizedNew<char>{handler}(pathMaxLen)};
diff --git a/flang-rt/lib/runtime/file.cpp b/flang-rt/lib/runtime/file.cpp
index 16e73db488727..8255ec8691886 100644
--- a/flang-rt/lib/runtime/file.cpp
+++ b/flang-rt/lib/runtime/file.cpp
@@ -60,10 +60,16 @@ static int openfile_mkstemp(IoErrorHandler &handler) {
   return fd;
 }
 
-void OpenFile::Open(OpenStatus status, Fortran::common::optional<Action> action,
+void OpenFile::Open(OpenStatus status, common::optional<Action> action,
     Position position, IoErrorHandler &handler) {
   if (fd_ >= 0 &&
       (status == OpenStatus::Old || status == OpenStatus::Unknown)) {
+    if (position == Position::Rewind) {
+      Seek(0, handler);
+    } else if (position == Position::Append) {
+      SeekToEnd(handler);
+    }
+    openPosition_ = position; // for INQUIRE(POSITION=)
     return;
   }
   CloseFd(handler);
@@ -131,8 +137,8 @@ void OpenFile::Open(OpenStatus status, Fortran::common::optional<Action> action,
   }
   RUNTIME_CHECK(handler, action.has_value());
   pending_.reset();
-  if (fd_ >= 0 && position == Position::Append && !RawSeekToEnd()) {
-    handler.SignalError(IostatOpenBadAppend);
+  if (fd_ >= 0 && position == Position::Append) {
+    SeekToEnd(handler);
   }
   isTerminal_ = fd_ >= 0 && IsATerminal(fd_);
   mayRead_ = *action != Action::Write;
@@ -322,7 +328,7 @@ int OpenFile::WriteAsynchronously(FileOffset at, const char *buffer,
 }
 
 void OpenFile::Wait(int id, IoErrorHandler &handler) {
-  Fortran::common::optional<int> ioStat;
+  common::optional<int> ioStat;
   Pending *prev{nullptr};
   for (Pending *p{pending_.get()}; p; p = (prev = p)->next.get()) {
     if (p->id == id) {
@@ -353,13 +359,13 @@ void OpenFile::WaitAll(IoErrorHandler &handler) {
   }
 }
 
-Position OpenFile::InquirePosition() const {
+Position OpenFile::InquirePosition(FileOffset offset) const {
   if (openPosition_) { // from OPEN statement
     return *openPosition_;
   } else { // unit has been repositioned since opening
-    if (position_ == knownSize_.value_or(position_ + 1)) {
+    if (offset == knownSize_.value_or(offset + 1)) {
       return Position::Append;
-    } else if (position_ == 0 && mayPosition_) {
+    } else if (offset == 0 && mayPosition_) {
       return Position::Rewind;
     } else {
       return Position::AsIs; // processor-dependent & no common behavior
@@ -391,7 +397,7 @@ bool OpenFile::RawSeek(FileOffset at) {
 #endif
 }
 
-bool OpenFile::RawSeekToEnd() {
+bool OpenFile::SeekToEnd(IoErrorHandler &handler) {
 #ifdef _LARGEFILE64_SOURCE
   std::int64_t at{::lseek64(fd_, 0, SEEK_END)};
 #else
@@ -399,8 +405,10 @@ bool OpenFile::RawSeekToEnd() {
 #endif
   if (at >= 0) {
     knownSize_ = at;
+    SetPosition(at);
     return true;
   } else {
+    handler.SignalError(IostatOpenBadAppend);
     return false;
   }
 }
diff --git a/flang-rt/lib/runtime/unit.h b/flang-rt/lib/runtime/unit.h
index f266a486bb708..34b7c3972bd96 100644
--- a/flang-rt/lib/runtime/unit.h
+++ b/flang-rt/lib/runtime/unit.h
@@ -197,6 +197,10 @@ class ExternalFileUnit : public ConnectionState,
 
   RT_API_ATTRS int GetAsynchronousId(IoErrorHandler &);
   RT_API_ATTRS bool Wait(int);
+  RT_API_ATTRS Position InquirePosition() const {
+    return OpenFile::InquirePosition(
+        static_cast<FileOffset>(frameOffsetInFile_ + recordOffsetInFrame_));
+  }
 
 private:
   static RT_API_ATTRS UnitMap &CreateUnitMap();



More information about the llvm-commits mailing list