[llvm] [flang][Runtime] Reset the information of namelist formatting when invoking child I/O (PR #218314)

Yusuke MINATO via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 23 21:23:19 PDT 2026


https://github.com/yus3710-fj created https://github.com/llvm/llvm-project/pull/218314

The flag of namelist formatting is enabled when IONAME(OutputNamelist) or IONAME(InputNamelist) is called, but it was never disabled afterward.
This patch disables the flag when invoking child I/O, as child I/O cannot use namelist formatting.

Fixes #201516

>From 87914ceac4d344a6dfe347e410af1928665b6ad3 Mon Sep 17 00:00:00 2001
From: Yusuke MINATO <minato.yusuke at fujitsu.com>
Date: Wed, 29 Jul 2026 17:08:36 +0900
Subject: [PATCH 1/2] [flang][Runtime] Reset the information of namelist
 formatting when invoking child I/O

---
 flang-rt/lib/runtime/io-stmt.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/flang-rt/lib/runtime/io-stmt.cpp b/flang-rt/lib/runtime/io-stmt.cpp
index 08931fc781428..aff36ece27ef7 100644
--- a/flang-rt/lib/runtime/io-stmt.cpp
+++ b/flang-rt/lib/runtime/io-stmt.cpp
@@ -988,7 +988,9 @@ template <Direction DIR>
 ChildIoStatementState<DIR>::ChildIoStatementState(
     ChildIo &child, const char *sourceFile, int sourceLine)
     : IoStatementBase{sourceFile, sourceLine}, child_{child},
-      mutableModes_{child.parent().mutableModes()} {}
+      mutableModes_{child.parent().mutableModes()} {
+  mutableModes_.inNamelist = false;
+}
 
 template <Direction DIR>
 const NonTbpDefinedIoTable *

>From c666657a7d8b792d6dd71dc1dae5a58dc257ce30 Mon Sep 17 00:00:00 2001
From: Yusuke MINATO <minato.yusuke at fujitsu.com>
Date: Wed, 5 Aug 2026 14:11:43 +0900
Subject: [PATCH 2/2] Add tests

---
 .../{lib => include/flang-rt}/runtime/unit.h  |  0
 flang-rt/lib/runtime/descriptor-io.cpp        |  2 +-
 flang-rt/lib/runtime/execute.cpp              |  2 +-
 flang-rt/lib/runtime/extensions.cpp           |  2 +-
 flang-rt/lib/runtime/external-unit.cpp        |  1 -
 flang-rt/lib/runtime/io-api-common.h          |  2 +-
 flang-rt/lib/runtime/io-api-minimal.cpp       |  2 +-
 flang-rt/lib/runtime/io-api.cpp               |  2 +-
 flang-rt/lib/runtime/io-stmt-minimal.cpp      |  2 +-
 flang-rt/lib/runtime/io-stmt.cpp              |  2 +-
 flang-rt/lib/runtime/pseudo-unit.cpp          |  2 +-
 flang-rt/lib/runtime/stop.cpp                 |  2 +-
 flang-rt/lib/runtime/unit-map.h               |  2 +-
 flang-rt/lib/runtime/unit.cpp                 |  2 +-
 flang-rt/test/Driver/iotype.f90               | 59 +++++++++++++++++++
 flang-rt/unittests/Runtime/CMakeLists.txt     |  1 +
 flang-rt/unittests/Runtime/ChildIO.cpp        | 35 +++++++++++
 17 files changed, 107 insertions(+), 13 deletions(-)
 rename flang-rt/{lib => include/flang-rt}/runtime/unit.h (100%)
 create mode 100644 flang-rt/test/Driver/iotype.f90
 create mode 100644 flang-rt/unittests/Runtime/ChildIO.cpp

diff --git a/flang-rt/lib/runtime/unit.h b/flang-rt/include/flang-rt/runtime/unit.h
similarity index 100%
rename from flang-rt/lib/runtime/unit.h
rename to flang-rt/include/flang-rt/runtime/unit.h
diff --git a/flang-rt/lib/runtime/descriptor-io.cpp b/flang-rt/lib/runtime/descriptor-io.cpp
index 79880f1e916ba..3b8a65d1ad9cf 100644
--- a/flang-rt/lib/runtime/descriptor-io.cpp
+++ b/flang-rt/lib/runtime/descriptor-io.cpp
@@ -9,12 +9,12 @@
 #include "descriptor-io.h"
 #include "edit-input.h"
 #include "edit-output.h"
-#include "unit.h"
 #include "flang-rt/runtime/descriptor.h"
 #include "flang-rt/runtime/io-stmt.h"
 #include "flang-rt/runtime/namelist.h"
 #include "flang-rt/runtime/terminator.h"
 #include "flang-rt/runtime/type-info.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang-rt/runtime/work-queue.h"
 #include "flang/Common/optional.h"
 #include "flang/Common/restorer.h"
diff --git a/flang-rt/lib/runtime/execute.cpp b/flang-rt/lib/runtime/execute.cpp
index 4fd6a1e060218..875cb597fa071 100644
--- a/flang-rt/lib/runtime/execute.cpp
+++ b/flang-rt/lib/runtime/execute.cpp
@@ -7,12 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang/Runtime/execute.h"
-#include "unit.h"
 #include "flang-rt/runtime/descriptor.h"
 #include "flang-rt/runtime/environment.h"
 #include "flang-rt/runtime/stat.h"
 #include "flang-rt/runtime/terminator.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 #include <cstdio>
 #include <cstdlib>
 #include <errno.h>
diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index ee084fdd72bd8..b159c7747726f 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -10,12 +10,12 @@
 // extensions that will eventually be implemented in Fortran.
 
 #include "flang/Runtime/extensions.h"
-#include "unit.h"
 #include "flang-rt/runtime/descriptor.h"
 #include "flang-rt/runtime/environment.h"
 #include "flang-rt/runtime/lock.h"
 #include "flang-rt/runtime/terminator.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang/Runtime/command.h"
 #include "flang/Runtime/entry-names.h"
 #include "flang/Runtime/io-api.h"
diff --git a/flang-rt/lib/runtime/external-unit.cpp b/flang-rt/lib/runtime/external-unit.cpp
index 25e6981334f75..b4eaf2e85fc9a 100644
--- a/flang-rt/lib/runtime/external-unit.cpp
+++ b/flang-rt/lib/runtime/external-unit.cpp
@@ -11,7 +11,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "unit-map.h"
-#include "unit.h"
 #include "flang-rt/runtime/io-error.h"
 #include "flang-rt/runtime/lock.h"
 #include "flang-rt/runtime/tools.h"
diff --git a/flang-rt/lib/runtime/io-api-common.h b/flang-rt/lib/runtime/io-api-common.h
index adf299e4bca53..040d26b7e3e4b 100644
--- a/flang-rt/lib/runtime/io-api-common.h
+++ b/flang-rt/lib/runtime/io-api-common.h
@@ -9,9 +9,9 @@
 #ifndef FLANG_RT_RUNTIME_IO_API_COMMON_H_
 #define FLANG_RT_RUNTIME_IO_API_COMMON_H_
 
-#include "unit.h"
 #include "flang-rt/runtime/io-stmt.h"
 #include "flang-rt/runtime/terminator.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang/Common/api-attrs.h"
 #include "flang/Common/optional.h"
 #include "flang/Runtime/io-api.h"
diff --git a/flang-rt/lib/runtime/io-api-minimal.cpp b/flang-rt/lib/runtime/io-api-minimal.cpp
index 299d87179f1a3..9c64754e66617 100644
--- a/flang-rt/lib/runtime/io-api-minimal.cpp
+++ b/flang-rt/lib/runtime/io-api-minimal.cpp
@@ -11,11 +11,11 @@
 
 #include "edit-output.h"
 #include "io-api-common.h"
-#include "unit.h"
 #include "flang-rt/runtime/format.h"
 #include "flang-rt/runtime/io-stmt.h"
 #include "flang-rt/runtime/terminator.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang/Runtime/io-api.h"
 
 namespace Fortran::runtime::io {
diff --git a/flang-rt/lib/runtime/io-api.cpp b/flang-rt/lib/runtime/io-api.cpp
index 2c97a39ea2555..28f16872ddada 100644
--- a/flang-rt/lib/runtime/io-api.cpp
+++ b/flang-rt/lib/runtime/io-api.cpp
@@ -18,7 +18,6 @@
 #include "edit-input.h"
 #include "edit-output.h"
 #include "io-api-common.h"
-#include "unit.h"
 #include "flang-rt/runtime/descriptor.h"
 #include "flang-rt/runtime/environment.h"
 #include "flang-rt/runtime/format.h"
@@ -26,6 +25,7 @@
 #include "flang-rt/runtime/memory.h"
 #include "flang-rt/runtime/terminator.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang/Common/optional.h"
 #include <cstdlib>
 #include <memory>
diff --git a/flang-rt/lib/runtime/io-stmt-minimal.cpp b/flang-rt/lib/runtime/io-stmt-minimal.cpp
index a0e91d37a3f37..ca52fbd168434 100644
--- a/flang-rt/lib/runtime/io-stmt-minimal.cpp
+++ b/flang-rt/lib/runtime/io-stmt-minimal.cpp
@@ -9,8 +9,8 @@
 // Implements the subset of the I/O statement API needed for basic
 // list-directed output (PRINT *) of intrinsic types.
 
-#include "unit.h"
 #include "flang-rt/runtime/io-stmt.h"
+#include "flang-rt/runtime/unit.h"
 #include <algorithm>
 
 namespace Fortran::runtime::io {
diff --git a/flang-rt/lib/runtime/io-stmt.cpp b/flang-rt/lib/runtime/io-stmt.cpp
index aff36ece27ef7..05032a1e9da34 100644
--- a/flang-rt/lib/runtime/io-stmt.cpp
+++ b/flang-rt/lib/runtime/io-stmt.cpp
@@ -7,12 +7,12 @@
 //===----------------------------------------------------------------------===//
 
 #include "flang-rt/runtime/io-stmt.h"
-#include "unit.h"
 #include "flang-rt/runtime/connection.h"
 #include "flang-rt/runtime/emit-encoded.h"
 #include "flang-rt/runtime/format.h"
 #include "flang-rt/runtime/memory.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang-rt/runtime/utf.h"
 #include <algorithm>
 #include <cstdio>
diff --git a/flang-rt/lib/runtime/pseudo-unit.cpp b/flang-rt/lib/runtime/pseudo-unit.cpp
index 7d6ddd9d8e2a4..c4ec1acaf7821 100644
--- a/flang-rt/lib/runtime/pseudo-unit.cpp
+++ b/flang-rt/lib/runtime/pseudo-unit.cpp
@@ -11,9 +11,9 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "unit.h"
 #include "flang-rt/runtime/io-error.h"
 #include "flang-rt/runtime/tools.h"
+#include "flang-rt/runtime/unit.h"
 
 #if defined(RT_USE_PSEUDO_FILE_UNIT)
 #include <cstdio>
diff --git a/flang-rt/lib/runtime/stop.cpp b/flang-rt/lib/runtime/stop.cpp
index 5abb80af7e66d..b4508e0b7d0bc 100644
--- a/flang-rt/lib/runtime/stop.cpp
+++ b/flang-rt/lib/runtime/stop.cpp
@@ -8,11 +8,11 @@
 
 #include "flang/Runtime/stop.h"
 #include "config.h"
-#include "unit.h"
 #include "flang-rt/runtime/environment.h"
 #include "flang-rt/runtime/file.h"
 #include "flang-rt/runtime/io-error.h"
 #include "flang-rt/runtime/terminator.h"
+#include "flang-rt/runtime/unit.h"
 #include <cfenv>
 #include <cstdio>
 #include <cstdlib>
diff --git a/flang-rt/lib/runtime/unit-map.h b/flang-rt/lib/runtime/unit-map.h
index fa61288a1e18d..f8e233e72d5bb 100644
--- a/flang-rt/lib/runtime/unit-map.h
+++ b/flang-rt/lib/runtime/unit-map.h
@@ -12,9 +12,9 @@
 #ifndef FLANG_RT_RUNTIME_UNIT_MAP_H_
 #define FLANG_RT_RUNTIME_UNIT_MAP_H_
 
-#include "unit.h"
 #include "flang-rt/runtime/lock.h"
 #include "flang-rt/runtime/memory.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang/Common/fast-int-set.h"
 #include <cstdint>
 #include <cstdlib>
diff --git a/flang-rt/lib/runtime/unit.cpp b/flang-rt/lib/runtime/unit.cpp
index c577ae7673127..c6839e1e19e48 100644
--- a/flang-rt/lib/runtime/unit.cpp
+++ b/flang-rt/lib/runtime/unit.cpp
@@ -10,7 +10,7 @@
 // RT_USE_PSEUDO_FILE_UNIT=0 and RT_USE_PSEUDO_FILE_UNIT=1.
 //
 //===----------------------------------------------------------------------===//
-#include "unit.h"
+#include "flang-rt/runtime/unit.h"
 #include "flang-rt/runtime/io-error.h"
 #include "flang-rt/runtime/lock.h"
 #include "flang-rt/runtime/tools.h"
diff --git a/flang-rt/test/Driver/iotype.f90 b/flang-rt/test/Driver/iotype.f90
new file mode 100644
index 0000000000000..aceb2a8682ab2
--- /dev/null
+++ b/flang-rt/test/Driver/iotype.f90
@@ -0,0 +1,59 @@
+! Verify that the value of iotype is correct when writing a derived type
+! with a derived type component to a namelist.
+
+! RUN: %flang %isysroot -L"%libdir" %s -o %t
+! RUN: env LD_LIBRARY_PATH="$LD_LIBRARY_PATH:%libdir" %t
+
+module iotype_mod
+  type ty2
+    integer :: x
+  contains
+    procedure :: type_2_prc
+    generic :: write(formatted) => type_2_prc
+  end type
+
+  type ty1
+    TYPE (ty2) :: t1
+  contains
+    procedure :: type_1_prc
+    generic :: write(formatted) => type_1_prc
+  end type
+
+  character(14) :: ch_iotype_1='xxxxxxx'
+  character(14) :: ch_iotype_2='yyyyyyy'
+contains
+  subroutine type_1_prc(dtv, unit, iotype, vlist, iostat, iomsg)
+    class(ty1), intent(in) :: dtv
+    integer, intent(in) :: unit
+    character(*), intent(in) :: iotype
+    integer, intent(in) :: vlist(:)
+    integer, intent(out) :: iostat
+    character(*), intent(inout) :: iomsg
+    ch_iotype_1 =iotype
+    write(unit,*,iostat=iostat,iomsg=iomsg) dtv%t1
+  end subroutine
+
+  subroutine type_2_prc(dtv, unit, iotype, vlist, iostat, iomsg)
+    class(ty2), intent(in) :: dtv
+    integer, intent(in) :: unit
+    character(*), intent(in) :: iotype
+    integer, intent(in) :: vlist(:)
+    integer, intent(out) :: iostat
+    character(*), intent(inout) :: iomsg
+    ch_iotype_2 =iotype
+    write(unit,*,iostat=iostat,iomsg=iomsg) dtv%x
+  end subroutine
+end module
+
+program main
+  USE iotype_mod
+  type(ty1) :: obj
+  namelist /NAME/obj
+  obj%t1%x=9
+
+  open(10,status="scratch")
+  WRITE(10,NML=NAME)
+
+  if (ch_iotype_1/='NAMELIST') error stop 1
+  if (ch_iotype_2/='LISTDIRECTED') error stop 2
+end program
diff --git a/flang-rt/unittests/Runtime/CMakeLists.txt b/flang-rt/unittests/Runtime/CMakeLists.txt
index ddabe346b54d1..112d864e26a53 100644
--- a/flang-rt/unittests/Runtime/CMakeLists.txt
+++ b/flang-rt/unittests/Runtime/CMakeLists.txt
@@ -13,6 +13,7 @@ add_flangrt_unittest(RuntimeTests
   Assign.cpp
   BufferTest.cpp
   CharacterTest.cpp
+  ChildIO.cpp
   CommandTest.cpp
   Complex.cpp
   CrashHandlerFixture.cpp
diff --git a/flang-rt/unittests/Runtime/ChildIO.cpp b/flang-rt/unittests/Runtime/ChildIO.cpp
new file mode 100644
index 0000000000000..27ee21c4d3395
--- /dev/null
+++ b/flang-rt/unittests/Runtime/ChildIO.cpp
@@ -0,0 +1,35 @@
+//===-- unittests/Runtime/ChildIO.cpp --------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrashHandlerFixture.h"
+#include "gtest/gtest.h"
+#include "flang-rt/runtime/unit.h"
+#include "flang/Runtime/io-api.h"
+
+using namespace Fortran::runtime;
+using namespace Fortran::runtime::io;
+
+struct ChildIOTests : CrashHandlerFixture {};
+
+TEST(ChildIOTests, InNamelist) {
+  // CHARACTER(LEN=10) :: output
+  static constexpr int bufferSize{10};
+  char output[bufferSize];
+
+  // WRITE(UNIT=output,NML=...)
+  Cookie parentCookie{IONAME(BeginInternalListOutput)(output, bufferSize)};
+  parentCookie->mutableModes().inNamelist = true;
+
+  // invoke child I/O (DTIO)
+  IoErrorHandler &handler{parentCookie->GetIoErrorHandler()};
+  ExternalFileUnit *newUnit{&ExternalFileUnit::NewUnit(handler, true)};
+  [[maybe_unused]] ChildIo &child{newUnit->PushChildIo(*parentCookie)};
+  Cookie childCookie{IONAME(BeginExternalListOutput)(
+      newUnit->unitNumber(), __FILE__, __LINE__)};
+  ASSERT_FALSE(childCookie->mutableModes().inNamelist);
+}



More information about the llvm-commits mailing list