Index: flang/runtime/io-api.cpp =================================================================== --- flang/runtime/io-api.cpp +++ flang/runtime/io-api.cpp @@ -304,7 +304,8 @@ Cookie IONAME(BeginOpenNewUnit)( // OPEN(NEWUNIT=j) const char *sourceFile, int sourceLine) { Terminator terminator{sourceFile, sourceLine}; - ExternalFileUnit &unit{ExternalFileUnit::NewUnit(terminator)}; + ExternalFileUnit &unit{ + ExternalFileUnit::NewUnit(terminator, false /*not child I/O*/)}; return &unit.BeginIoStatement( unit, false /*was an existing file*/, sourceFile, sourceLine); } Index: flang/runtime/unit-map.h =================================================================== --- flang/runtime/unit-map.h +++ flang/runtime/unit-map.h @@ -14,7 +14,9 @@ #include "lock.h" #include "unit.h" +#include "flang/Common/constexpr-bitset.h" #include "flang/Runtime/memory.h" +#include #include namespace Fortran::runtime::io { @@ -40,10 +42,7 @@ return Find(path); } - ExternalFileUnit &NewUnit(const Terminator &terminator) { - CriticalSection critical{lock_}; - return Create(nextNewUnit_--, terminator); - } + ExternalFileUnit &NewUnit(const Terminator &); // To prevent races, the unit is removed from the map if it exists, // and put on the closing_ list until DestroyClosed() is called. @@ -84,7 +83,7 @@ Lock lock_; OwningPtr bucket_[buckets_]{}; // all owned by *this - int nextNewUnit_{-1000}; // see 12.5.6.12 in Fortran 2018 + common::BitSet<64> busyNewUnits_; OwningPtr closing_{nullptr}; // units during CLOSE statement }; } // namespace Fortran::runtime::io Index: flang/runtime/unit-map.cpp =================================================================== --- flang/runtime/unit-map.cpp +++ flang/runtime/unit-map.cpp @@ -10,6 +10,21 @@ namespace Fortran::runtime::io { +// See 12.5.6.12 in Fortran 2018. NEWUNIT= unit numbers are negative, +// and not equal -1 (or ERROR_UNIT, if it were negative, which it isn't.) +ExternalFileUnit &UnitMap::NewUnit(const Terminator &terminator) { + CriticalSection critical{lock_}; + std::optional n; + n = (~busyNewUnits_).LeastElement(); + if (!n.has_value()) { + terminator.Crash( + "No available unit number for NEWUNIT= or internal child I/O"); + } + busyNewUnits_.set(*n); + // bit position 0 <-> unit -2; kind=1 units are in [-65..-2] + return Create(static_cast(-2 - *n), terminator); +} + ExternalFileUnit *UnitMap::LookUpForClose(int n) { CriticalSection critical{lock_}; Chain *previous{nullptr}; @@ -36,6 +51,10 @@ Chain *previous{nullptr}; for (p = closing_.get(); p; previous = p, p = p->next.get()) { if (&p->unit == &unit) { + int n{unit.unitNumber()}; + if (n <= -2) { + busyNewUnits_.reset(static_cast(-2 - n)); + } if (previous) { previous->next.swap(p->next); } else { Index: flang/runtime/unit.h =================================================================== --- flang/runtime/unit.h +++ flang/runtime/unit.h @@ -50,7 +50,7 @@ static ExternalFileUnit *LookUp(const char *path); static ExternalFileUnit &CreateNew(int unit, const Terminator &); static ExternalFileUnit *LookUpForClose(int unit); - static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo = false); + static ExternalFileUnit &NewUnit(const Terminator &, bool forChildIo); static void CloseAll(IoErrorHandler &); static void FlushAll(IoErrorHandler &);