[flang][runtime] FLUSH(bad or unconnected unit number) is an error
authorPeter Klausler <pklausler@nvidia.com>
Wed, 22 Jun 2022 20:24:51 +0000 (13:24 -0700)
committerPeter Klausler <pklausler@nvidia.com>
Thu, 23 Jun 2022 18:08:53 +0000 (11:08 -0700)
Some I/O control statements are no-ops when attempted on a bad or
unconnected UNIT=, but the standard says that FLUSH is an error
in that case.

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

flang/include/flang/Runtime/iostat.h
flang/runtime/io-api.cpp
flang/runtime/iostat.cpp

index bd38e74..6d6be7c 100644 (file)
@@ -81,6 +81,7 @@ enum Iostat {
   IostatTooManyAsyncOps,
   IostatBadBackspaceUnit,
   IostatBadUnitNumber,
+  IostatBadFlushUnit,
 };
 
 const char *IostatErrorString(int);
index f3efaa9..60e52e5 100644 (file)
@@ -147,6 +147,18 @@ Cookie IONAME(BeginInternalFormattedInput)(const char *internal,
       format, formatLength, scratchArea, scratchBytes, sourceFile, sourceLine);
 }
 
+static Cookie NoopUnit(const Terminator &terminator, int unitNumber,
+    enum Iostat iostat = IostatOk) {
+  Cookie cookie{&New<NoopStatementState>{terminator}(
+      terminator.sourceFileName(), terminator.sourceLine(), unitNumber)
+                     .release()
+                     ->ioStatementState()};
+  if (iostat != IostatOk) {
+    cookie->GetIoErrorHandler().SetPendingError(iostat);
+  }
+  return cookie;
+}
+
 static ExternalFileUnit *GetOrCreateUnit(int unitNumber, Direction direction,
     std::optional<bool> isUnformatted, const Terminator &terminator,
     Cookie &errorCookie) {
@@ -156,11 +168,7 @@ static ExternalFileUnit *GetOrCreateUnit(int unitNumber, Direction direction,
     errorCookie = nullptr;
     return unit;
   } else {
-    errorCookie = &New<NoopStatementState>{terminator}(
-        terminator.sourceFileName(), terminator.sourceLine(), unitNumber)
-                       .release()
-                       ->ioStatementState();
-    errorCookie->GetIoErrorHandler().SetPendingError(IostatBadUnitNumber);
+    errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
     return nullptr;
   }
 }
@@ -358,12 +366,7 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
     return &unit->BeginIoStatement<OpenStatementState>(
         *unit, wasExtant, sourceFile, sourceLine);
   } else {
-    auto &io{
-        New<NoopStatementState>{terminator}(sourceFile, sourceLine, unitNumber)
-            .release()
-            ->ioStatementState()};
-    io.GetIoErrorHandler().SetPendingError(IostatBadUnitNumber);
-    return &io;
+    return NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
   }
 }
 
@@ -378,7 +381,6 @@ Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
 
 Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,
     const char *sourceFile, int sourceLine) {
-  Terminator terminator{sourceFile, sourceLine};
   if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
     if (unit->Wait(id)) {
       return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
@@ -388,14 +390,9 @@ Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,
           IostatBadWaitId, unit, sourceFile, sourceLine);
     }
   } else {
-    auto &io{
-        New<NoopStatementState>{terminator}(sourceFile, sourceLine, unitNumber)
-            .release()
-            ->ioStatementState()};
-    if (id != 0) {
-      io.GetIoErrorHandler().SetPendingError(IostatBadWaitUnit);
-    }
-    return &io;
+    Terminator terminator{sourceFile, sourceLine};
+    return NoopUnit(
+        terminator, unitNumber, id == 0 ? IostatOk : IostatBadWaitUnit);
   }
 }
 Cookie IONAME(BeginWaitAll)(
@@ -410,10 +407,8 @@ Cookie IONAME(BeginClose)(
         *unit, sourceFile, sourceLine);
   } else {
     // CLOSE(UNIT=bad unit) is just a no-op
-    Terminator oom{sourceFile, sourceLine};
-    return &New<NoopStatementState>{oom}(sourceFile, sourceLine, unitNumber)
-                .release()
-                ->ioStatementState();
+    Terminator terminator{sourceFile, sourceLine};
+    return NoopUnit(terminator, unitNumber);
   }
 }
 
@@ -423,11 +418,10 @@ Cookie IONAME(BeginFlush)(
     return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
         *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine);
   } else {
-    // FLUSH(UNIT=unknown) is a no-op
-    Terminator oom{sourceFile, sourceLine};
-    return &New<NoopStatementState>{oom}(sourceFile, sourceLine, unitNumber)
-                .release()
-                ->ioStatementState();
+    // FLUSH(UNIT=bad unit) is an error; an unconnected unit is a no-op
+    Terminator terminator{sourceFile, sourceLine};
+    return NoopUnit(terminator, unitNumber,
+        unitNumber >= 0 ? IostatOk : IostatBadFlushUnit);
   }
 }
 
@@ -438,12 +432,7 @@ Cookie IONAME(BeginBackspace)(
     return &unit->BeginIoStatement<ExternalMiscIoStatementState>(
         *unit, ExternalMiscIoStatementState::Backspace, sourceFile, sourceLine);
   } else {
-    auto &io{
-        New<NoopStatementState>{terminator}(sourceFile, sourceLine, unitNumber)
-            .release()
-            ->ioStatementState()};
-    io.GetIoErrorHandler().SetPendingError(IostatBadBackspaceUnit);
-    return &io;
+    return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit);
   }
 }
 
index d39f9b6..747a776 100644 (file)
@@ -87,7 +87,7 @@ const char *IostatErrorString(int iostat) {
     return "READ/WRITE(ASYNCHRONOUS='YES') on unit without "
            "OPEN(ASYNCHRONOUS='YES')";
   case IostatBadWaitUnit:
-    return "WAIT(UNIT=) for a bad unit number";
+    return "WAIT(UNIT=) for a bad or unconnected unit number";
   case IostatBOZInputOverflow:
     return "B/O/Z input value overflows variable";
   case IostatIntegerInputOverflow:
@@ -107,6 +107,8 @@ const char *IostatErrorString(int iostat) {
     return "BACKSPACE on unconnected unit";
   case IostatBadUnitNumber:
     return "Negative unit number is not allowed";
+  case IostatBadFlushUnit:
+    return "FLUSH attempted on a bad or unconnected unit number";
   default:
     return nullptr;
   }