diff --git a/flang-rt/include/flang-rt/runtime/environment.h b/flang-rt/include/flang-rt/runtime/environment.h index b91cf629509ae..72157fe4418ec 100644 --- a/flang-rt/include/flang-rt/runtime/environment.h +++ b/flang-rt/include/flang-rt/runtime/environment.h @@ -73,6 +73,7 @@ struct ExecutionEnvironment { bool noStopMessage{false}; // NO_STOP_MESSAGE=1 inhibits "Fortran STOP" bool defaultUTF8{false}; // DEFAULT_UTF8 bool checkPointerDeallocation{true}; // FORT_CHECK_POINTER_DEALLOCATION + bool truncateStream{true}; // FORT_TRUNCATE_STREAM enum InternalDebugging { WorkQueue = 1 }; int internalDebugging{0}; // FLANG_RT_DEBUG diff --git a/flang-rt/lib/runtime/environment.cpp b/flang-rt/lib/runtime/environment.cpp index 2a2e19f9f17ec..be4f7308ab027 100644 --- a/flang-rt/lib/runtime/environment.cpp +++ b/flang-rt/lib/runtime/environment.cpp @@ -141,6 +141,17 @@ void ExecutionEnvironment::Configure(int ac, const char *av[], } } + if (auto *x{std::getenv("FORT_TRUNCATE_STREAM")}) { + char *end; + auto n{std::strtol(x, &end, 10)}; + if (n >= 0 && n <= 1 && *end == '\0') { + truncateStream = n != 0; + } else { + std::fprintf(stderr, + "Fortran runtime: FORT_TRUNCATE_STREAM=%s is invalid; ignored\n", x); + } + } + if (auto *x{std::getenv("NO_STOP_MESSAGE")}) { char *end; auto n{std::strtol(x, &end, 10)}; diff --git a/flang-rt/lib/runtime/unit.cpp b/flang-rt/lib/runtime/unit.cpp index 549fbeaca05b3..bc98cfdcbe5d2 100644 --- a/flang-rt/lib/runtime/unit.cpp +++ b/flang-rt/lib/runtime/unit.cpp @@ -783,8 +783,11 @@ void ExternalFileUnit::DoEndfile(IoErrorHandler &handler) { frameOffsetInFile_ += recordOffsetInFrame_ + furthestPositionInRecord; recordOffsetInFrame_ = 0; FlushOutput(handler); - Truncate(frameOffsetInFile_, handler); - TruncateFrame(frameOffsetInFile_, handler); + if (access != Access::Stream || executionEnvironment.truncateStream) { + // Stream output after positioning truncates with some compilers. + Truncate(frameOffsetInFile_, handler); + TruncateFrame(frameOffsetInFile_, handler); + } BeginRecord(); impliedEndfile_ = false; anyWriteSinceLastPositioning_ = false; diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index c9cc02703fbc8..593cd99147515 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -946,6 +946,17 @@ print *, [(j,j=1,10)] This design allows format-driven input with `DT` editing to retain control over advancement in child input, while otherwise allowing it. +* When output takes place to a file under `ACCESS="STREAM"` after + repositioning it to an earlier position, some compilers will + truncate the file; this behavior is similar to the implicit + `ENDFILE` that takes place under sequential output after a + `BACKSPACE` or `REWIND` statement. + Truncation of streams is not specified in the standard, however, + and it does not take place with all compilers. + In this one, truncation is optional; it occurs by default, + but it can be disabled via `FORT_TRUNCATE_STREAM=0` in the + environment at execution time. + ## De Facto Standard Features * `EXTENDS_TYPE_OF()` returns `.TRUE.` if both of its arguments have the diff --git a/flang/docs/RuntimeEnvironment.md b/flang/docs/RuntimeEnvironment.md index c7a3dfbb2af1d..ccc401c51e8a3 100644 --- a/flang/docs/RuntimeEnvironment.md +++ b/flang/docs/RuntimeEnvironment.md @@ -55,3 +55,14 @@ The default is 72. Set `NO_STOP_MESSAGE=1` to disable the extra information about IEEE floating-point exception flags that the Fortran language standard requires for `STOP` and `ERROR STOP` statements. + +## `FORT_TRUNCATE_STREAM` + +Set `FORT_TRUNCATE_STREAM=1` to make output to a formatted unit +with `ACCESS="STREAM"` truncate the file when the unit has been +repositioned via `POS=` to an earlier point in the file. +This behavior is analogous to the implicit writing of an ENDFILE record +when output takes place to a sequential unit after +executing a `BACKSPACE` or `REWIND` statement. +Truncation of a stream-access unit is common to several other +compilers, but it is not mentioned in the standard.