diff --git a/flang/include/flang/Runtime/iostat.h b/flang/include/flang/Runtime/iostat.h index ddb82ce0ca238..faadaab8e90ff 100644 --- a/flang/include/flang/Runtime/iostat.h +++ b/flang/include/flang/Runtime/iostat.h @@ -83,6 +83,7 @@ enum Iostat { IostatBadUnitNumber, IostatBadFlushUnit, IostatBadOpOnChildUnit, + IostatBadNewUnit, }; const char *IostatErrorString(int); diff --git a/flang/runtime/io-api.cpp b/flang/runtime/io-api.cpp index fe58bbc75f832..2c17f10e77693 100644 --- a/flang/runtime/io-api.cpp +++ b/flang/runtime/io-api.cpp @@ -379,8 +379,8 @@ Cookie IONAME(BeginOpenUnit)( // OPEN(without NEWUNIT=) IostatBadOpOnChildUnit, nullptr /* no unit */, sourceFile, sourceLine); } else { - return &unit->BeginIoStatement( - terminator, *unit, wasExtant, sourceFile, sourceLine); + return &unit->BeginIoStatement(terminator, *unit, + wasExtant, false /*not NEWUNIT=*/, sourceFile, sourceLine); } } else { return NoopUnit(terminator, unitNumber, IostatBadUnitNumber); @@ -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( - terminator, unit, false /*was an existing file*/, sourceFile, sourceLine); + return &unit.BeginIoStatement(terminator, unit, + false /*was an existing file*/, true /*NEWUNIT=*/, sourceFile, + sourceLine); } Cookie IONAME(BeginWait)(ExternalUnit unitNumber, AsynchronousId id, diff --git a/flang/runtime/io-stmt.cpp b/flang/runtime/io-stmt.cpp index d18f81b93faf2..4be7e6135c04f 100644 --- a/flang/runtime/io-stmt.cpp +++ b/flang/runtime/io-stmt.cpp @@ -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), diff --git a/flang/runtime/io-stmt.h b/flang/runtime/io-stmt.h index 33653e69ad4ed..fa432d07a680d 100644 --- a/flang/runtime/io-stmt.h +++ b/flang/runtime/io-stmt.h @@ -537,10 +537,10 @@ class ChildUnformattedIoStatementState : public ChildIoStatementState { // 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= @@ -555,6 +555,7 @@ class OpenStatementState : public ExternalIoStatementBase { private: bool wasExtant_; + bool isNewUnit_; std::optional status_; std::optional position_; std::optional action_; diff --git a/flang/runtime/iostat.cpp b/flang/runtime/iostat.cpp index f34bde28be9d0..d786e505433f8 100644 --- a/flang/runtime/iostat.cpp +++ b/flang/runtime/iostat.cpp @@ -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; }