Skip to content

Commit

Permalink
[flang][runtime] Detect NEWUNIT= without FILE= or STATUS='SCRATCH'
Browse files Browse the repository at this point in the history
It is an error to open a new unit with OPEN(NEWUNIT=) and have
neither a file name nor a scratch status.  Catch it, and report a
new error code.

Differential Revision: https://reviews.llvm.org/D155967
  • Loading branch information
klausler committed Jul 21, 2023
1 parent 25d3421 commit afdbf1b
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 7 deletions.
1 change: 1 addition & 0 deletions flang/include/flang/Runtime/iostat.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum Iostat {
IostatBadUnitNumber,
IostatBadFlushUnit,
IostatBadOpOnChildUnit,
IostatBadNewUnit,
};

const char *IostatErrorString(int);
Expand Down
9 changes: 5 additions & 4 deletions flang/runtime/io-api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,8 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=)
IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile,
sourceLine);
} else {
return &unit->BeginIoStatement<OpenStatementState>(
terminator, *unit, wasExtant, sourceFile, sourceLine);
return &unit->BeginIoStatement<OpenStatementState>(terminator, *unit,
wasExtant, false /*not NEWUNIT=*/, sourceFile, sourceLine);
}
} else {
return NoopUnit(terminator, unitNumber, IostatBadUnitNumber);
Expand All @@ -392,8 +392,9 @@ Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j)
Terminator terminator{sourceFile, sourceLine};
ExternalFileUnit &unit{
ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)};
return &unit.BeginIoStatement<OpenStatementState>(
terminator, unit, false /*was an existing file*/, sourceFile, sourceLine);
return &unit.BeginIoStatement<OpenStatementState>(terminator, unit,
false /*was an existing file*/, true /*NEWUNIT=*/, sourceFile,
sourceLine);
}

Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id,
Expand Down
6 changes: 6 additions & 0 deletions flang/runtime/io-stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ void OpenStatementState::CompleteOperation() {
SignalError("FILE= may not appear on OPEN with STATUS='SCRATCH'");
}
}
// F'2023 12.5.6.13 - NEWUNIT= requires either FILE= or STATUS='SCRATCH'
if (isNewUnit_ && !path_.get() &&
status_.value_or(OpenStatus::Unknown) != OpenStatus::Scratch) {
SignalError(IostatBadNewUnit);
status_ = OpenStatus::Scratch; // error recovery
}
if (path_.get() || wasExtant_ ||
(status_ && *status_ == OpenStatus::Scratch)) {
unit().OpenUnit(status_, action_, position_.value_or(Position::AsIs),
Expand Down
7 changes: 4 additions & 3 deletions flang/runtime/io-stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -537,10 +537,10 @@ class ChildUnformattedIoStatementState : public ChildIoStatementState<DIR> {
// OPEN
class OpenStatementState : public ExternalIoStatementBase {
public:
OpenStatementState(ExternalFileUnit &unit, bool wasExtant,
OpenStatementState(ExternalFileUnit &unit, bool wasExtant, bool isNewUnit,
const char *sourceFile = nullptr, int sourceLine = 0)
: ExternalIoStatementBase{unit, sourceFile, sourceLine}, wasExtant_{
wasExtant} {}
: ExternalIoStatementBase{unit, sourceFile, sourceLine},
wasExtant_{wasExtant}, isNewUnit_{isNewUnit} {}
bool wasExtant() const { return wasExtant_; }
void set_status(OpenStatus status) { status_ = status; } // STATUS=
void set_path(const char *, std::size_t); // FILE=
Expand All @@ -555,6 +555,7 @@ class OpenStatementState : public ExternalIoStatementBase {

private:
bool wasExtant_;
bool isNewUnit_;
std::optional<OpenStatus> status_;
std::optional<Position> position_;
std::optional<Action> action_;
Expand Down
2 changes: 2 additions & 0 deletions flang/runtime/iostat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ const char *IostatErrorString(int iostat) {
return "FLUSH attempted on a bad or unconnected unit number";
case IostatBadOpOnChildUnit:
return "Impermissible I/O statement on child I/O unit";
case IostatBadNewUnit:
return "NEWUNIT= without FILE= or STATUS='SCRATCH'";
default:
return nullptr;
}
Expand Down

0 comments on commit afdbf1b

Please sign in to comment.