[flang] [llvm] [flang][runtime] Control stream truncation via runtime environment (PR #168415)
Peter Klausler via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 17 10:11:05 PST 2025
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/168415
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.
>From 8700ba149ff0b6d782df344bf276ae810af71542 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
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.
More information about the llvm-commits
mailing list