[flang] [llvm] [flang][runtime] OPEN(STATUS='NEW') should fail on extant file (PR #180605)
Peter Klausler via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 9 14:48:06 PST 2026
https://github.com/klausler updated https://github.com/llvm/llvm-project/pull/180605
>From 5108dc9161253eed1c4dd33319cd75aec45a0ca3 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Mon, 9 Feb 2026 11:53:15 -0800
Subject: [PATCH] [flang][runtime] OPEN(STATUS='NEW') should fail on extant
file
An OPEN(..., STATUS='NEW') statement should fail when the named
file exists, and also should not delete it when the failure is a
recoverable error.
---
flang-rt/lib/runtime/file.cpp | 9 +++++
flang-rt/lib/runtime/iostat.cpp | 2 ++
flang-rt/unittests/Runtime/ExternalIOTest.cpp | 34 +++++++++++++++++++
flang/include/flang/Runtime/iostat-consts.h | 1 +
4 files changed, 46 insertions(+)
diff --git a/flang-rt/lib/runtime/file.cpp b/flang-rt/lib/runtime/file.cpp
index 8255ec8691886..1122f1ee43d88 100644
--- a/flang-rt/lib/runtime/file.cpp
+++ b/flang-rt/lib/runtime/file.cpp
@@ -99,6 +99,9 @@ void OpenFile::Open(OpenStatus status, common::optional<Action> action,
}
if (status == OpenStatus::New) {
flags |= O_EXCL;
+ if (!action) {
+ action = Action::ReadWrite;
+ }
} else if (status == OpenStatus::Replace) {
flags |= O_TRUNC;
}
@@ -131,6 +134,12 @@ void OpenFile::Open(OpenStatus status, common::optional<Action> action,
}
fd_ = ::open(path_.get(), flags, 0600);
if (fd_ < 0) {
+ if (errno == EEXIST && status == OpenStatus::New) {
+ handler.SignalError(IostatOpenNewExtant,
+ "OPEN(STATUS='NEW') on existing file '%s'", path_.get());
+ path_.reset(); // prevent unlink
+ return;
+ }
handler.SignalErrno();
}
}
diff --git a/flang-rt/lib/runtime/iostat.cpp b/flang-rt/lib/runtime/iostat.cpp
index c2577e7caf0e1..202b40d6abdcd 100644
--- a/flang-rt/lib/runtime/iostat.cpp
+++ b/flang-rt/lib/runtime/iostat.cpp
@@ -119,6 +119,8 @@ const char *IostatErrorString(int iostat) {
return "List-directed input value has trailing unused characters";
case IostatNonExternalDefinedUnformattedIo:
return "Defined unformatted I/O without an external unit";
+ case IostatOpenNewExtant:
+ return "OPEN(STATUS='NEW') on existing file";
default:
return nullptr;
}
diff --git a/flang-rt/unittests/Runtime/ExternalIOTest.cpp b/flang-rt/unittests/Runtime/ExternalIOTest.cpp
index 6421194f45141..82c3fc38ef161 100644
--- a/flang-rt/unittests/Runtime/ExternalIOTest.cpp
+++ b/flang-rt/unittests/Runtime/ExternalIOTest.cpp
@@ -951,3 +951,37 @@ TEST(ExternalIOTests, BigUnitNumbers) {
EXPECT_EQ(std::strncmp(msg, expectedMsg, n), 0);
}
}
+
+TEST(ExternalIOTests, OpenNewExtant) {
+ // OPEN(10,STATUS='REPLACE')
+ Cookie io{IONAME(BeginOpenUnit)(10, __FILE__, __LINE__)};
+ ASSERT_TRUE(IONAME(SetFile)(io, "opennewextant", 13))
+ << "SetFile(opennewextant)";
+ ASSERT_TRUE(IONAME(SetStatus)(io, "REPLACE", 7)) << "SetStatus(REPLACE)";
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+ << "EndIoStatement() for OpenUnit(REPLACE)";
+ // CLOSE(10)
+ io = IONAME(BeginClose)(10, __FILE__, __LINE__);
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+ << "EndIoStatement() for Close";
+ // OPEN(10,STATUS='NEW') - should fail
+ io = IONAME(BeginOpenUnit)(10, __FILE__, __LINE__);
+ ASSERT_TRUE(IONAME(SetFile)(io, "opennewextant", 13))
+ << "SetFile(opennewextant)";
+ ASSERT_TRUE(IONAME(SetStatus)(io, "NEW", 3)) << "SetStatus(NEW)";
+ IONAME(EnableHandlers)(io, /*hasIoStat=*/true);
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOpenNewExtant)
+ << "EndIoStatement() for OpenUnit(NEW)";
+ // OPEN(10,STATUS='OLD')
+ io = IONAME(BeginOpenUnit)(10, __FILE__, __LINE__);
+ ASSERT_TRUE(IONAME(SetFile)(io, "opennewextant", 15))
+ << "SetFile(opennewextant)";
+ ASSERT_TRUE(IONAME(SetStatus)(io, "OLD", 3)) << "SetStatus(OLD)";
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+ << "EndIoStatement() for OpenUnit(OLD)";
+ // CLOSE(UNIT=10,STATUS='DELETE')
+ io = IONAME(BeginClose)(10, __FILE__, __LINE__);
+ ASSERT_TRUE(IONAME(SetStatus)(io, "DELETE", 6)) << "SetStatus(DELETE)";
+ ASSERT_EQ(IONAME(EndIoStatement)(io), IostatOk)
+ << "EndIoStatement() for CLOSE(DELETE)";
+}
diff --git a/flang/include/flang/Runtime/iostat-consts.h b/flang/include/flang/Runtime/iostat-consts.h
index 47093d971bf77..bc627424eb1c3 100644
--- a/flang/include/flang/Runtime/iostat-consts.h
+++ b/flang/include/flang/Runtime/iostat-consts.h
@@ -85,6 +85,7 @@ enum Iostat {
IostatBadNewUnit,
IostatBadListDirectedInputSeparator,
IostatNonExternalDefinedUnformattedIo,
+ IostatOpenNewExtant,
};
} // namespace Fortran::runtime::io
More information about the llvm-commits
mailing list