From 8700ba149ff0b6d782df344bf276ae810af71542 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Mon, 17 Nov 2025 10:02:36 -0800 Subject: [PATCH] [flang][runtime] Control stream truncation via runtime environment The ISO Fortran standards don't say whether a WRITE to a formatted stream unit should truncate the unit if there has been any repositioning (via POS= control list specifiers) to an earlier point in the stream. But units with sequential records do truncate on writes after BACKSPACE and REWIND statements, and many compilers (including this one) truncate stream units too. Since some compilers don't truncate streams, this patch adds an environment variable FORT_TRUNCATE_STREAM that can be set to 0 to disable truncation and ease porting to flang-new of codes that depend on that behavior. Fixes https://github.com/llvm/llvm-project/issues/167569. --- flang-rt/include/flang-rt/runtime/environment.h | 1 + flang-rt/lib/runtime/environment.cpp | 11 +++++++++++ flang-rt/lib/runtime/unit.cpp | 7 +++++-- flang/docs/Extensions.md | 11 +++++++++++ flang/docs/RuntimeEnvironment.md | 11 +++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) 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.