[flang-commits] [flang] 80cdf0d - [flang] Correct INQUIRE(POSITION= & PAD=)

Peter Klausler via flang-commits flang-commits at lists.llvm.org
Tue Nov 30 13:51:55 PST 2021


Author: Peter Klausler
Date: 2021-11-30T13:51:48-08:00
New Revision: 80cdf0db67e2c0f231f4fefc2b873690b44f84cc

URL: https://github.com/llvm/llvm-project/commit/80cdf0db67e2c0f231f4fefc2b873690b44f84cc
DIFF: https://github.com/llvm/llvm-project/commit/80cdf0db67e2c0f231f4fefc2b873690b44f84cc.diff

LOG: [flang] Correct INQUIRE(POSITION= & PAD=)

INQUIRE(POSITION=)'s results need to reflect the POSITION=
specifier used for the OPEN statement until the unit has been
repositioned.  Preserve the POSITION= from OPEN and used it
for INQUIRE(POSITION=) until is becomes obsolete.

INQUIRE(PAD=) is implemented here in the case of an unconnected unit
with Fortran 2018 semantics; i.e., "UNDEFINED", rather than Fortran 90's
"YES"/"NO" (see 4.3.6 para 2).  Apparent failures with F'90-only tests
will persist with INQUIRE(PAD=); these discrepancies don't seem to warrant
an option or environment variable.

To make the implementation of INQUIRE more closely match the language
in the standard, rename IsOpen() to IsConnected(), and use it explicitly
for the various INQUIRE specifiers.

Differential Revision: https://reviews.llvm.org/D114755

Added: 
    

Modified: 
    flang/runtime/connection.h
    flang/runtime/file.cpp
    flang/runtime/file.h
    flang/runtime/io-stmt.cpp
    flang/runtime/unit.cpp
    flang/runtime/unit.h

Removed: 
    


################################################################################
diff  --git a/flang/runtime/connection.h b/flang/runtime/connection.h
index 0eb2038500b24..6e7e0a6b17dc0 100644
--- a/flang/runtime/connection.h
+++ b/flang/runtime/connection.h
@@ -25,7 +25,8 @@ enum class Access { Sequential, Direct, Stream };
 inline bool IsRecordFile(Access a) { return a != Access::Stream; }
 
 // These characteristics of a connection are immutable after being
-// established in an OPEN statement.
+// established in an OPEN statement, except for recordLength,
+// which is immutable only when isFixedRecordLength is true.
 struct ConnectionAttributes {
   Access access{Access::Sequential}; // ACCESS='SEQUENTIAL', 'DIRECT', 'STREAM'
   std::optional<bool> isUnformatted; // FORM='UNFORMATTED' if true

diff  --git a/flang/runtime/file.cpp b/flang/runtime/file.cpp
index b8e349be8a21b..aaa2e30f4d17c 100644
--- a/flang/runtime/file.cpp
+++ b/flang/runtime/file.cpp
@@ -149,6 +149,7 @@ void OpenFile::Open(OpenStatus status, std::optional<Action> action,
     knownSize_ = 0;
     mayPosition_ = true;
   }
+  openPosition_ = position; // for INQUIRE(POSITION=)
 }
 
 void OpenFile::Predefine(int fd) {
@@ -208,7 +209,7 @@ std::size_t OpenFile::Read(FileOffset at, char *buffer, std::size_t minBytes,
         break;
       }
     } else {
-      position_ += chunk;
+      SetPosition(position_ + chunk);
       got += chunk;
     }
   }
@@ -228,7 +229,7 @@ std::size_t OpenFile::Write(FileOffset at, const char *buffer,
   while (put < bytes) {
     auto chunk{::write(fd_, buffer + put, bytes - put)};
     if (chunk >= 0) {
-      position_ += chunk;
+      SetPosition(position_ + chunk);
       put += chunk;
     } else {
       auto err{errno};
@@ -351,6 +352,20 @@ void OpenFile::WaitAll(IoErrorHandler &handler) {
   }
 }
 
+Position OpenFile::InquirePosition() const {
+  if (openPosition_) { // from OPEN statement
+    return *openPosition_;
+  } else { // unit has been repositioned since opening
+    if (position_ == knownSize_.value_or(position_ + 1)) {
+      return Position::Append;
+    } else if (position_ == 0 && mayPosition_) {
+      return Position::Rewind;
+    } else {
+      return Position::AsIs; // processor-dependent & no common behavior
+    }
+  }
+}
+
 void OpenFile::CheckOpen(const Terminator &terminator) {
   RUNTIME_CHECK(terminator, fd_ >= 0);
 }
@@ -359,7 +374,7 @@ bool OpenFile::Seek(FileOffset at, IoErrorHandler &handler) {
   if (at == position_) {
     return true;
   } else if (RawSeek(at)) {
-    position_ = at;
+    SetPosition(at);
     return true;
   } else {
     handler.SignalErrno();

diff  --git a/flang/runtime/file.h b/flang/runtime/file.h
index 3770b190ee741..cde3c194de94e 100644
--- a/flang/runtime/file.h
+++ b/flang/runtime/file.h
@@ -39,7 +39,7 @@ class OpenFile {
   bool isTerminal() const { return isTerminal_; }
   std::optional<FileOffset> knownSize() const { return knownSize_; }
 
-  bool IsOpen() const { return fd_ >= 0; }
+  bool IsConnected() const { return fd_ >= 0; }
   void Open(OpenStatus, std::optional<Action>, Position, IoErrorHandler &);
   void Predefine(int fd);
   void Close(CloseStatus, IoErrorHandler &);
@@ -66,6 +66,9 @@ class OpenFile {
   void Wait(int id, IoErrorHandler &);
   void WaitAll(IoErrorHandler &);
 
+  // INQUIRE(POSITION=)
+  Position InquirePosition() const;
+
 private:
   struct Pending {
     int id;
@@ -78,6 +81,10 @@ class OpenFile {
   bool RawSeek(FileOffset);
   bool RawSeekToEnd();
   int PendingResult(const Terminator &, int);
+  void SetPosition(FileOffset pos) {
+    position_ = pos;
+    openPosition_.reset();
+  }
 
   int fd_{-1};
   OwningPtr<char> path_;
@@ -86,6 +93,7 @@ class OpenFile {
   bool mayWrite_{false};
   bool mayPosition_{false};
   bool mayAsynchronous_{false};
+  std::optional<Position> openPosition_; // from Open(); reset after positioning
   FileOffset position_{0};
   std::optional<FileOffset> knownSize_;
   bool isTerminal_{false};

diff  --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp
index 10560bfb5b30b..d003390bf1070 100644
--- a/flang/runtime/io-stmt.cpp
+++ b/flang/runtime/io-stmt.cpp
@@ -824,26 +824,35 @@ bool InquireUnitState::Inquire(
   const char *str{nullptr};
   switch (inquiry) {
   case HashInquiryKeyword("ACCESS"):
-    switch (unit().access) {
-    case Access::Sequential:
-      str = "SEQUENTIAL";
-      break;
-    case Access::Direct:
-      str = "DIRECT";
-      break;
-    case Access::Stream:
-      str = "STREAM";
-      break;
+    if (!unit().IsConnected()) {
+      str = "UNDEFINED";
+    } else {
+      switch (unit().access) {
+      case Access::Sequential:
+        str = "SEQUENTIAL";
+        break;
+      case Access::Direct:
+        str = "DIRECT";
+        break;
+      case Access::Stream:
+        str = "STREAM";
+        break;
+      }
     }
     break;
   case HashInquiryKeyword("ACTION"):
-    str = unit().mayWrite() ? unit().mayRead() ? "READWRITE" : "WRITE" : "READ";
+    str = !unit().IsConnected() ? "UNDEFINED"
+        : unit().mayWrite()     ? unit().mayRead() ? "READWRITE" : "WRITE"
+                                : "READ";
     break;
   case HashInquiryKeyword("ASYNCHRONOUS"):
-    str = unit().mayAsynchronous() ? "YES" : "NO";
+    str = !unit().IsConnected()    ? "UNDEFINED"
+        : unit().mayAsynchronous() ? "YES"
+                                   : "NO";
     break;
   case HashInquiryKeyword("BLANK"):
-    str = unit().isUnformatted.value_or(true)   ? "UNDEFINED"
+    str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
+        ? "UNDEFINED"
         : unit().modes.editingFlags & blankZero ? "ZERO"
                                                 : "NULL";
     break;
@@ -854,12 +863,13 @@ bool InquireUnitState::Inquire(
     str = unit().swapEndianness() ? "SWAP" : "NATIVE";
     break;
   case HashInquiryKeyword("DECIMAL"):
-    str = unit().isUnformatted.value_or(true)      ? "UNDEFINED"
+    str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
+        ? "UNDEFINED"
         : unit().modes.editingFlags & decimalComma ? "COMMA"
                                                    : "POINT";
     break;
   case HashInquiryKeyword("DELIM"):
-    if (unit().isUnformatted.value_or(true)) {
+    if (!unit().IsConnected() || unit().isUnformatted.value_or(true)) {
       str = "UNDEFINED";
     } else {
       switch (unit().modes.delim) {
@@ -876,23 +886,26 @@ bool InquireUnitState::Inquire(
     }
     break;
   case HashInquiryKeyword("DIRECT"):
-    str = unit().access == Access::Direct ||
+    str = !unit().IsConnected() ? "UNKNOWN"
+        : unit().access == Access::Direct ||
             (unit().mayPosition() && unit().isFixedRecordLength)
         ? "YES"
         : "NO";
     break;
   case HashInquiryKeyword("ENCODING"):
-    str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
+    str = !unit().IsConnected()               ? "UNKNOWN"
+        : unit().isUnformatted.value_or(true) ? "UNDEFINED"
         : unit().isUTF8                       ? "UTF-8"
                                               : "ASCII";
     break;
   case HashInquiryKeyword("FORM"):
-    str = !unit().isUnformatted ? "UNDEFINED"
-        : *unit().isUnformatted ? "UNFORMATTED"
-                                : "FORMATTED";
+    str = !unit().IsConnected() || !unit().isUnformatted ? "UNDEFINED"
+        : *unit().isUnformatted                          ? "UNFORMATTED"
+                                                         : "FORMATTED";
     break;
   case HashInquiryKeyword("FORMATTED"):
-    str = !unit().isUnformatted ? "UNKNOWN"
+    str = !unit().IsConnected() ? "UNDEFINED"
+        : !unit().isUnformatted ? "UNKNOWN"
         : *unit().isUnformatted ? "NO"
                                 : "YES";
     break;
@@ -903,33 +916,38 @@ bool InquireUnitState::Inquire(
     }
     break;
   case HashInquiryKeyword("PAD"):
-    str = unit().isUnformatted.value_or(true) ? "UNDEFINED"
-        : unit().modes.pad                    ? "YES"
-                                              : "NO";
+    str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
+        ? "UNDEFINED"
+        : unit().modes.pad ? "YES"
+                           : "NO";
     break;
   case HashInquiryKeyword("POSITION"):
-    if (unit().access == Access::Direct) {
+    if (!unit().IsConnected() || unit().access == Access::Direct) {
       str = "UNDEFINED";
     } else {
-      auto size{unit().knownSize()};
-      auto pos{unit().position()};
-      if (pos == size.value_or(pos + 1)) {
-        str = "APPEND";
-      } else if (pos == 0 && unit().mayPosition()) {
+      switch (unit().InquirePosition()) {
+      case Position::Rewind:
         str = "REWIND";
-      } else {
-        str = "ASIS"; // processor-dependent & no common behavior
+        break;
+      case Position::Append:
+        str = "APPEND";
+        break;
+      case Position::AsIs:
+        str = "ASIS";
+        break;
       }
     }
     break;
   case HashInquiryKeyword("READ"):
-    str = unit().mayRead() ? "YES" : "NO";
+    str = !unit().IsConnected() ? "UNDEFINED" : unit().mayRead() ? "YES" : "NO";
     break;
   case HashInquiryKeyword("READWRITE"):
-    str = unit().mayRead() && unit().mayWrite() ? "YES" : "NO";
+    str = !unit().IsConnected()                 ? "UNDEFINED"
+        : unit().mayRead() && unit().mayWrite() ? "YES"
+                                                : "NO";
     break;
   case HashInquiryKeyword("ROUND"):
-    if (unit().isUnformatted.value_or(true)) {
+    if (!unit().IsConnected() || unit().isUnformatted.value_or(true)) {
       str = "UNDEFINED";
     } else {
       switch (unit().modes.round) {
@@ -954,23 +972,28 @@ bool InquireUnitState::Inquire(
   case HashInquiryKeyword("SEQUENTIAL"):
     // "NO" for Direct, since Sequential would not work if
     // the unit were reopened without RECL=.
-    str = unit().access == Access::Sequential ? "YES" : "NO";
+    str = !unit().IsConnected()               ? "UNKNOWN"
+        : unit().access == Access::Sequential ? "YES"
+                                              : "NO";
     break;
   case HashInquiryKeyword("SIGN"):
-    str = unit().isUnformatted.value_or(true)  ? "UNDEFINED"
+    str = !unit().IsConnected() || unit().isUnformatted.value_or(true)
+        ? "UNDEFINED"
         : unit().modes.editingFlags & signPlus ? "PLUS"
                                                : "SUPPRESS";
     break;
   case HashInquiryKeyword("STREAM"):
-    str = unit().access == Access::Stream ? "YES" : "NO";
-    break;
-  case HashInquiryKeyword("WRITE"):
-    str = unit().mayWrite() ? "YES" : "NO";
+    str = !unit().IsConnected()           ? "UNKNOWN"
+        : unit().access == Access::Stream ? "YES"
+                                          : "NO";
     break;
   case HashInquiryKeyword("UNFORMATTED"):
-    str = !unit().isUnformatted ? "UNKNOWN"
-        : *unit().isUnformatted ? "YES"
-                                : "NO";
+    str = !unit().IsConnected() || !unit().isUnformatted ? "UNKNOWN"
+        : *unit().isUnformatted                          ? "YES"
+                                                         : "NO";
+    break;
+  case HashInquiryKeyword("WRITE"):
+    str = !unit().IsConnected() ? "UNKNOWN" : unit().mayWrite() ? "YES" : "NO";
     break;
   }
   if (str) {
@@ -991,7 +1014,7 @@ bool InquireUnitState::Inquire(InquiryKeywordHash inquiry, bool &result) {
     result = unit().path() != nullptr;
     return true;
   case HashInquiryKeyword("OPENED"):
-    result = true;
+    result = unit().IsConnected();
     return true;
   case HashInquiryKeyword("PENDING"):
     result = false; // asynchronous I/O is not implemented
@@ -1023,13 +1046,15 @@ bool InquireUnitState::Inquire(
     }
     return true;
   case HashInquiryKeyword("NUMBER"):
-    result = unit().unitNumber();
+    result = unit().IsConnected() ? unit().unitNumber() : -1;
     return true;
   case HashInquiryKeyword("POS"):
     result = unit().position();
     return true;
   case HashInquiryKeyword("RECL"):
-    if (unit().access == Access::Stream) {
+    if (!unit().IsConnected()) {
+      result = -1;
+    } else if (unit().access == Access::Stream) {
       result = -2;
     } else if (unit().isFixedRecordLength && unit().recordLength) {
       result = *unit().recordLength;
@@ -1038,10 +1063,11 @@ bool InquireUnitState::Inquire(
     }
     return true;
   case HashInquiryKeyword("SIZE"):
-    if (auto size{unit().knownSize()}) {
-      result = *size;
-    } else {
-      result = -1;
+    result = -1;
+    if (unit().IsConnected()) {
+      if (auto size{unit().knownSize()}) {
+        result = *size;
+      }
     }
     return true;
   default:

diff  --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp
index e24914bc5fa68..f1d2b2ca95fe6 100644
--- a/flang/runtime/unit.cpp
+++ b/flang/runtime/unit.cpp
@@ -107,7 +107,7 @@ void ExternalFileUnit::OpenUnit(std::optional<OpenStatus> status,
   swapEndianness_ = convert == Convert::Swap ||
       (convert == Convert::LittleEndian && !isHostLittleEndian) ||
       (convert == Convert::BigEndian && isHostLittleEndian);
-  if (IsOpen()) {
+  if (IsConnected()) {
     bool isSamePath{newPath.get() && path() && pathLength() == newPathLength &&
         std::memcmp(path(), newPath.get(), newPathLength) == 0};
     if (status && *status != OpenStatus::Old && isSamePath) {

diff  --git a/flang/runtime/unit.h b/flang/runtime/unit.h
index 4f7a18ebc1650..a63921c9db75d 100644
--- a/flang/runtime/unit.h
+++ b/flang/runtime/unit.h
@@ -35,6 +35,8 @@ class ExternalFileUnit : public ConnectionState,
                          public FileFrame<ExternalFileUnit> {
 public:
   explicit ExternalFileUnit(int unitNumber) : unitNumber_{unitNumber} {}
+  ~ExternalFileUnit() {}
+
   int unitNumber() const { return unitNumber_; }
   bool swapEndianness() const { return swapEndianness_; }
   bool createdForInternalChildIo() const { return createdForInternalChildIo_; }


        


More information about the flang-commits mailing list