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 @@ -111,8 +111,8 @@ if (unitNumber == DefaultUnit) { unitNumber = DIR == Direction::Input ? 5 : 6; } - ExternalFileUnit &unit{ - ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( + unitNumber, DIR, false /*formatted*/, terminator)}; if (unit.access == Access::Direct) { terminator.Crash("List-directed I/O attempted on direct access file"); return nullptr; @@ -150,8 +150,8 @@ if (unitNumber == DefaultUnit) { unitNumber = DIR == Direction::Input ? 5 : 6; } - ExternalFileUnit &unit{ - ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( + unitNumber, DIR, false /*formatted*/, terminator)}; if (unit.isUnformatted) { terminator.Crash("Formatted I/O attempted on unformatted file"); return nullptr; @@ -185,8 +185,8 @@ Cookie BeginUnformattedIO( ExternalUnit unitNumber, const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; - ExternalFileUnit &unit{ - ExternalFileUnit::LookUpOrCrash(unitNumber, terminator)}; + ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreateAnonymous( + unitNumber, DIR, true /*unformatted*/, terminator)}; if (!unit.isUnformatted) { terminator.Crash("Unformatted output attempted on formatted file"); } @@ -223,7 +223,7 @@ bool wasExtant{false}; Terminator terminator{sourceFile, sourceLine}; ExternalFileUnit &unit{ - ExternalFileUnit::LookUpOrCreate(unitNumber, terminator, &wasExtant)}; + ExternalFileUnit::LookUpOrCreate(unitNumber, terminator, wasExtant)}; return &unit.BeginIoStatement( unit, wasExtant, sourceFile, sourceLine); } @@ -231,10 +231,11 @@ Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j) const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; + bool ignored{false}; ExternalFileUnit &unit{ExternalFileUnit::LookUpOrCreate( - ExternalFileUnit::NewUnit(terminator), terminator)}; + ExternalFileUnit::NewUnit(terminator), terminator, ignored)}; return &unit.BeginIoStatement( - unit, false /*wasExtant*/, sourceFile, sourceLine); + unit, false /*was an existing file*/, sourceFile, sourceLine); } Cookie IONAME(BeginClose)( diff --git a/flang/runtime/unit-map.h b/flang/runtime/unit-map.h --- a/flang/runtime/unit-map.h +++ b/flang/runtime/unit-map.h @@ -27,16 +27,11 @@ } ExternalFileUnit &LookUpOrCreate( - int n, const Terminator &terminator, bool *wasExtant) { + int n, const Terminator &terminator, bool &wasExtant) { CriticalSection critical{lock_}; auto *p{Find(n)}; - if (wasExtant) { - *wasExtant = p != nullptr; - } - if (p) { - return *p; - } - return Create(n, terminator); + wasExtant = p != nullptr; + return p ? *p : Create(n, terminator); } ExternalFileUnit &NewUnit(const Terminator &terminator) { diff --git a/flang/runtime/unit.h b/flang/runtime/unit.h --- a/flang/runtime/unit.h +++ b/flang/runtime/unit.h @@ -39,7 +39,10 @@ static ExternalFileUnit *LookUp(int unit); static ExternalFileUnit &LookUpOrCrash(int unit, const Terminator &); static ExternalFileUnit &LookUpOrCreate( - int unit, const Terminator &, bool *wasExtant = nullptr); + int unit, const Terminator &, bool &wasExtant); + static ExternalFileUnit &LookUpOrCreateAnonymous( + int unit, Direction, bool isUnformatted, const Terminator &); + static ExternalFileUnit &CreateNew(int unit, const Terminator &); static ExternalFileUnit *LookUpForClose(int unit); static int NewUnit(const Terminator &); static void CloseAll(IoErrorHandler &); diff --git a/flang/runtime/unit.cpp b/flang/runtime/unit.cpp --- a/flang/runtime/unit.cpp +++ b/flang/runtime/unit.cpp @@ -10,6 +10,7 @@ #include "io-error.h" #include "lock.h" #include "unit-map.h" +#include namespace Fortran::runtime::io { @@ -46,10 +47,38 @@ } ExternalFileUnit &ExternalFileUnit::LookUpOrCreate( - int unit, const Terminator &terminator, bool *wasExtant) { + int unit, const Terminator &terminator, bool &wasExtant) { return GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant); } +ExternalFileUnit &ExternalFileUnit::LookUpOrCreateAnonymous( + int unit, Direction dir, bool isUnformatted, const Terminator &terminator) { + bool exists{false}; + ExternalFileUnit &result{ + GetUnitMap().LookUpOrCreate(unit, terminator, exists)}; + if (!exists) { + // I/O to an unconnected unit reads/creates a local file, e.g. fort.7 + std::size_t pathMaxLen{32}; + auto path{SizedNew{terminator}(pathMaxLen)}; + std::snprintf(path.get(), pathMaxLen, "fort.%d", unit); + IoErrorHandler handler{terminator}; + result.OpenUnit( + dir == Direction::Input ? OpenStatus::Old : OpenStatus::Replace, + Position::Rewind, std::move(path), std::strlen(path.get()), handler); + result.isUnformatted = isUnformatted; + } + return result; +} + +ExternalFileUnit &ExternalFileUnit::CreateNew( + int unit, const Terminator &terminator) { + bool wasExtant{false}; + ExternalFileUnit &result{ + GetUnitMap().LookUpOrCreate(unit, terminator, wasExtant)}; + RUNTIME_CHECK(terminator, !wasExtant); + return result; +} + ExternalFileUnit *ExternalFileUnit::LookUpForClose(int unit) { return GetUnitMap().LookUpForClose(unit); } @@ -155,14 +184,14 @@ Terminator terminator{__FILE__, __LINE__}; IoErrorHandler handler{terminator}; unitMap = New{terminator}().release(); - ExternalFileUnit &out{ExternalFileUnit::LookUpOrCreate(6, terminator)}; + ExternalFileUnit &out{ExternalFileUnit::CreateNew(6, terminator)}; out.Predefine(1); out.set_mayRead(false); out.set_mayWrite(true); out.set_mayPosition(false); out.SetDirection(Direction::Output, handler); defaultOutput = &out; - ExternalFileUnit &in{ExternalFileUnit::LookUpOrCreate(5, terminator)}; + ExternalFileUnit &in{ExternalFileUnit::CreateNew(5, terminator)}; in.Predefine(0); in.set_mayRead(true); in.set_mayWrite(false);