[flang][runtime] Allow recovery from BACKSPACE(badUnit)
authorPeter Klausler <pklausler@nvidia.com>
Thu, 9 Jun 2022 21:31:03 +0000 (14:31 -0700)
committerPeter Klausler <pklausler@nvidia.com>
Wed, 15 Jun 2022 20:00:54 +0000 (13:00 -0700)
When an unconnected unit number is used in a BACKSPACE statement
with ERR=, IOSTAT=, &/or IOMSG= control specifiers, don't crash,
but let the program deal with the error.

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

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

index cfde044..1ae6890 100644 (file)
@@ -79,6 +79,7 @@ enum Iostat {
   IostatCannotReposition,
   IostatBadWaitId,
   IostatTooManyAsyncOps,
+  IostatBadBackspaceUnit,
 };
 
 const char *IostatErrorString(int);
index 42f4c2b..af79757 100644 (file)
@@ -395,10 +395,17 @@ Cookie IONAME(BeginFlush)(
 Cookie IONAME(BeginBackspace)(
     ExternalUnit unitNumber, const char *sourceFile, int sourceLine) {
   Terminator terminator{sourceFile, sourceLine};
-  ExternalFileUnit &unit{
-      ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)};
-  return &unit.BeginIoStatement<ExternalMiscIoStatementState>(
-      unit, ExternalMiscIoStatementState::Backspace, sourceFile, sourceLine);
+  if (ExternalFileUnit * unit{ExternalFileUnit::LookUp(unitNumber)}) {
+    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;
+  }
 }
 
 Cookie IONAME(BeginEndfile)(
index 480cbea..3bc3eba 100644 (file)
@@ -287,6 +287,7 @@ int CloseStatementState::EndIoStatement() {
 }
 
 void NoUnitIoStatementState::CompleteOperation() {
+  SignalPendingError();
   IoStatementBase::CompleteOperation();
 }
 
index 5e3209b..d343abe 100644 (file)
@@ -590,7 +590,8 @@ private:
   CloseStatus status_{CloseStatus::Keep};
 };
 
-// For CLOSE(bad unit), WAIT(bad unit, ID=nonzero) and INQUIRE(unconnected unit)
+// For CLOSE(bad unit), WAIT(bad unit, ID=nonzero), INQUIRE(unconnected unit),
+// and recoverable BACKSPACE(bad unit)
 class NoUnitIoStatementState : public IoStatementBase {
 public:
   IoStatementState &ioStatementState() { return ioStatementState_; }
index 3008c6e..a1df37a 100644 (file)
@@ -103,6 +103,8 @@ const char *IostatErrorString(int iostat) {
     return "WAIT(ID=nonzero) for an ID value that is not a pending operation";
   case IostatTooManyAsyncOps:
     return "Too many asynchronous operations pending on unit";
+  case IostatBadBackspaceUnit:
+    return "BACKSPACE on unconnected unit";
   default:
     return nullptr;
   }
index 27ad178..036ff9b 100644 (file)
@@ -43,15 +43,6 @@ ExternalFileUnit *ExternalFileUnit::LookUp(int unit) {
   return GetUnitMap().LookUp(unit);
 }
 
-ExternalFileUnit &ExternalFileUnit::LookUpOrCrash(
-    int unit, const Terminator &terminator) {
-  ExternalFileUnit *file{LookUp(unit)};
-  if (!file) {
-    terminator.Crash("%d is not an open I/O unit number", unit);
-  }
-  return *file;
-}
-
 ExternalFileUnit &ExternalFileUnit::LookUpOrCreate(
     int unit, const Terminator &terminator, bool &wasExtant) {
   return GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant);
index 3d024ba..dca5e29 100644 (file)
@@ -47,7 +47,6 @@ public:
   bool createdForInternalChildIo() const { return createdForInternalChildIo_; }
 
   static ExternalFileUnit *LookUp(int unit);
-  static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &);
   static ExternalFileUnit &LookUpOrCreate(
       int unit, const Terminator &, bool &wasExtant);
   static ExternalFileUnit &LookUpOrCreateAnonymous(int unit, Direction,