[flang][runtime] FLUSH(bad or unconnected unit number) is an error

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
This commit is contained in:
Peter Klausler 2022-06-22 13:24:51 -07:00
parent c50e6f590c
commit c078e464a0
3 changed files with 28 additions and 36 deletions

View File

@ -81,6 +81,7 @@ enum Iostat {
IostatTooManyAsyncOps,
IostatBadBackspaceUnit,
IostatBadUnitNumber,
IostatBadFlushUnit,
};
const char *IostatErrorString(int);

View 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);
}
}

View 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;
}