diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -81,6 +81,7 @@ IostatTooManyAsyncOps, IostatBadBackspaceUnit, IostatBadUnitNumber, + IostatBadFlushUnit, }; const char *IostatErrorString(int); diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -147,6 +147,18 @@ format, formatLength, scratchArea, scratchBytes, sourceFile, sourceLine); } +static Cookie NoopUnit(const Terminator &terminator, int unitNumber, + enum Iostat iostat = IostatOk) { + Cookie cookie{&New{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 isUnformatted, const Terminator &terminator, Cookie &errorCookie) { @@ -156,11 +168,7 @@ errorCookie = nullptr; return unit; } else { - errorCookie = &New{terminator}( - terminator.sourceFileName(), terminator.sourceLine(), unitNumber) - .release() - ->ioStatementState(); - errorCookie->GetIoErrorHandler().SetPendingError(IostatBadUnitNumber); + errorCookie = NoopUnit(terminator, unitNumber, IostatBadUnitNumber); return nullptr; } } @@ -358,12 +366,7 @@ return &unit->BeginIoStatement( *unit, wasExtant, sourceFile, sourceLine); } else { - auto &io{ - New{terminator}(sourceFile, sourceLine, unitNumber) - .release() - ->ioStatementState()}; - io.GetIoErrorHandler().SetPendingError(IostatBadUnitNumber); - return &io; + return NoopUnit(terminator, unitNumber, IostatBadUnitNumber); } } @@ -378,7 +381,6 @@ 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( @@ -388,14 +390,9 @@ IostatBadWaitId, unit, sourceFile, sourceLine); } } else { - auto &io{ - New{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 @@ *unit, sourceFile, sourceLine); } else { // CLOSE(UNIT=bad unit) is just a no-op - Terminator oom{sourceFile, sourceLine}; - return &New{oom}(sourceFile, sourceLine, unitNumber) - .release() - ->ioStatementState(); + Terminator terminator{sourceFile, sourceLine}; + return NoopUnit(terminator, unitNumber); } } @@ -423,11 +418,10 @@ return &unit->BeginIoStatement( *unit, ExternalMiscIoStatementState::Flush, sourceFile, sourceLine); } else { - // FLUSH(UNIT=unknown) is a no-op - Terminator oom{sourceFile, sourceLine}; - return &New{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 @@ return &unit->BeginIoStatement( *unit, ExternalMiscIoStatementState::Backspace, sourceFile, sourceLine); } else { - auto &io{ - New{terminator}(sourceFile, sourceLine, unitNumber) - .release() - ->ioStatementState()}; - io.GetIoErrorHandler().SetPendingError(IostatBadBackspaceUnit); - return &io; + return NoopUnit(terminator, unitNumber, IostatBadBackspaceUnit); } } diff --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp --- a/flang/runtime/iostat.cpp +++ b/flang/runtime/iostat.cpp @@ -87,7 +87,7 @@ 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 @@ 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; }