Skip to content

Commit

Permalink
[flang] Predefine unit 0 connected to stderr
Browse files Browse the repository at this point in the history
This is a near-universal language extension; external unit 0
is preconnected to the standard error output.

Differential Revision: https://reviews.llvm.org/D114298
  • Loading branch information
klausler committed Nov 22, 2021
1 parent e7cee55 commit a62b601
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
2 changes: 2 additions & 0 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ end
if an actual argument acceptable to one could not be passed to
the other & vice versa because exactly one is polymorphic or
exactly one is unlimited polymorphic).
* External unit 0 is predefined and connected to the standard error output,
and defined as `ERROR_UNIT` in the intrinsic `ISO_FORTRAN_ENV` module.

### Extensions supported when enabled by options

Expand Down
2 changes: 1 addition & 1 deletion flang/module/iso_fortran_env.f90
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ module iso_fortran_env
integer, parameter :: current_team = -1, initial_team = -2, parent_team = -3

integer, parameter :: input_unit = 5, output_unit = 6
integer, parameter :: error_unit = output_unit
integer, parameter :: error_unit = 0
integer, parameter :: iostat_end = -1, iostat_eor = -2
integer, parameter :: iostat_inquire_internal_unit = -1

Expand Down
35 changes: 28 additions & 7 deletions flang/runtime/unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@ namespace Fortran::runtime::io {
// should work without a Fortran main program.
static Lock unitMapLock;
static UnitMap *unitMap{nullptr};
static ExternalFileUnit *defaultInput{nullptr};
static ExternalFileUnit *defaultOutput{nullptr};
static ExternalFileUnit *defaultInput{nullptr}; // unit 5
static ExternalFileUnit *defaultOutput{nullptr}; // unit 6
static ExternalFileUnit *errorOutput{nullptr}; // unit 0 extension

void FlushOutputOnCrash(const Terminator &terminator) {
if (!defaultOutput) {
if (!defaultOutput && !errorOutput) {
return;
}
IoErrorHandler handler{terminator};
handler.HasIoStat(); // prevent nested crash if flush has error
CriticalSection critical{unitMapLock};
if (defaultOutput) {
IoErrorHandler handler{terminator};
handler.HasIoStat(); // prevent nested crash if flush has error
defaultOutput->FlushOutput(handler);
}
if (errorOutput) {
errorOutput->FlushOutput(handler);
}
}

ExternalFileUnit *ExternalFileUnit::LookUp(int unit) {
Expand Down Expand Up @@ -210,19 +214,29 @@ UnitMap &ExternalFileUnit::GetUnitMap() {
Terminator terminator{__FILE__, __LINE__};
IoErrorHandler handler{terminator};
UnitMap *newUnitMap{New<UnitMap>{terminator}().release()};

bool wasExtant{false};
ExternalFileUnit &out{newUnitMap->LookUpOrCreate(6, terminator, wasExtant)};
RUNTIME_CHECK(terminator, !wasExtant);
out.Predefine(1);
out.SetDirection(Direction::Output, handler);
out.isUnformatted = false;
defaultOutput = &out;

ExternalFileUnit &in{newUnitMap->LookUpOrCreate(5, terminator, wasExtant)};
RUNTIME_CHECK(terminator, !wasExtant);
in.Predefine(0);
in.SetDirection(Direction::Input, handler);
in.isUnformatted = false;
defaultInput = &in;

ExternalFileUnit &error{newUnitMap->LookUpOrCreate(0, terminator, wasExtant)};
RUNTIME_CHECK(terminator, !wasExtant);
error.Predefine(2);
error.SetDirection(Direction::Output, handler);
error.isUnformatted = false;
errorOutput = &error;

// TODO: Set UTF-8 mode from the environment
unitMap = newUnitMap;
return *unitMap;
Expand All @@ -235,6 +249,8 @@ void ExternalFileUnit::CloseAll(IoErrorHandler &handler) {
FreeMemoryAndNullify(unitMap);
}
defaultOutput = nullptr;
defaultInput = nullptr;
errorOutput = nullptr;
}

void ExternalFileUnit::FlushAll(IoErrorHandler &handler) {
Expand Down Expand Up @@ -627,8 +643,13 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(

void ExternalFileUnit::BeginSequentialVariableFormattedInputRecord(
IoErrorHandler &handler) {
if (this == defaultInput && defaultOutput) {
defaultOutput->FlushOutput(handler);
if (this == defaultInput) {
if (defaultOutput) {
defaultOutput->FlushOutput(handler);
}
if (errorOutput) {
errorOutput->FlushOutput(handler);
}
}
std::size_t length{0};
do {
Expand Down

0 comments on commit a62b601

Please sign in to comment.