[llvm] [flang][runtime] Fix child input bugs under NAMELIST (PR #151571)

Peter Klausler via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 31 11:18:08 PDT 2025


https://github.com/klausler created https://github.com/llvm/llvm-project/pull/151571

When NAMELIST input takes place on a derived type, we need to preserve the type in the descriptor that is created for storage sequence association.  Further, the fact that any child list input in within the context of a NAMELIST must be inherited so that input fields don't try to consume later "variable=" strings.

Fixes https://github.com/llvm/llvm-project/issues/151222.

>From 392c2fe11637aa322fc424ff0acb28dd1b1a8809 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Thu, 31 Jul 2025 11:11:58 -0700
Subject: [PATCH] [flang][runtime] Fix child input bugs under NAMELIST

When NAMELIST input takes place on a derived type, we need to
preserve the type in the descriptor that is created for storage
sequence association.  Further, the fact that any child list input
in within the context of a NAMELIST must be inherited so that
input fields don't try to consume later "variable=" strings.

Fixes https://github.com/llvm/llvm-project/issues/151222.
---
 flang-rt/include/flang-rt/runtime/descriptor.h |  3 +++
 flang-rt/include/flang-rt/runtime/io-stmt.h    |  7 +++++--
 flang-rt/lib/runtime/descriptor-io.cpp         |  2 +-
 flang-rt/lib/runtime/descriptor.cpp            |  6 +++++-
 flang-rt/lib/runtime/io-stmt.cpp               | 16 ++++++++++++++++
 flang-rt/lib/runtime/namelist.cpp              |  8 ++++++++
 6 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/descriptor.h b/flang-rt/include/flang-rt/runtime/descriptor.h
index bc5a5b5f14697..f04b38220ecdc 100644
--- a/flang-rt/include/flang-rt/runtime/descriptor.h
+++ b/flang-rt/include/flang-rt/runtime/descriptor.h
@@ -101,6 +101,9 @@ class DescriptorAddendum {
   explicit RT_API_ATTRS DescriptorAddendum(
       const typeInfo::DerivedType *dt = nullptr)
       : derivedType_{dt}, len_{0} {}
+  RT_API_ATTRS DescriptorAddendum(const DescriptorAddendum &that) {
+    *this = that;
+  }
   RT_API_ATTRS DescriptorAddendum &operator=(const DescriptorAddendum &);
 
   RT_API_ATTRS const typeInfo::DerivedType *derivedType() const {
diff --git a/flang-rt/include/flang-rt/runtime/io-stmt.h b/flang-rt/include/flang-rt/runtime/io-stmt.h
index 1d680d7d2ffb3..0b3194da0ab4c 100644
--- a/flang-rt/include/flang-rt/runtime/io-stmt.h
+++ b/flang-rt/include/flang-rt/runtime/io-stmt.h
@@ -461,6 +461,9 @@ class ListDirectedStatementState<Direction::Input>
     inNamelistSequence_ = inNamelistSequence;
   }
 
+protected:
+  bool inNamelistSequence_{false};
+
 private:
   int remaining_{0}; // for "r*" repetition
   Fortran::common::optional<SavedPosition> repeatPosition_;
@@ -468,7 +471,6 @@ class ListDirectedStatementState<Direction::Input>
   bool hitSlash_{false}; // once '/' is seen, nullify further items
   bool realPart_{false};
   bool imaginaryPart_{false};
-  bool inNamelistSequence_{false};
 };
 
 template <Direction DIR>
@@ -688,7 +690,8 @@ template <Direction DIR>
 class ChildListIoStatementState : public ChildIoStatementState<DIR>,
                                   public ListDirectedStatementState<DIR> {
 public:
-  using ChildIoStatementState<DIR>::ChildIoStatementState;
+  RT_API_ATTRS ChildListIoStatementState(
+      ChildIo &, const char *sourceFile = nullptr, int sourceLine = 0);
   using ListDirectedStatementState<DIR>::GetNextDataEdit;
   RT_API_ATTRS int EndIoStatement();
 };
diff --git a/flang-rt/lib/runtime/descriptor-io.cpp b/flang-rt/lib/runtime/descriptor-io.cpp
index e22fc79e03abc..a60d0b90da467 100644
--- a/flang-rt/lib/runtime/descriptor-io.cpp
+++ b/flang-rt/lib/runtime/descriptor-io.cpp
@@ -110,7 +110,7 @@ static RT_API_ATTRS Fortran::common::optional<bool> DefinedFormattedIo(
     Fortran::common::optional<std::int64_t> startPos;
     if (edit.descriptor == DataEdit::DefinedDerivedType &&
         special.which() == typeInfo::SpecialBinding::Which::ReadFormatted) {
-      // DT is an edit descriptor so everything that the child
+      // DT is an edit descriptor, so everything that the child
       // I/O subroutine reads counts towards READ(SIZE=).
       startPos = io.InquirePos();
     }
diff --git a/flang-rt/lib/runtime/descriptor.cpp b/flang-rt/lib/runtime/descriptor.cpp
index 021440cbdd0f6..c895f6af5b02d 100644
--- a/flang-rt/lib/runtime/descriptor.cpp
+++ b/flang-rt/lib/runtime/descriptor.cpp
@@ -231,6 +231,7 @@ RT_API_ATTRS bool Descriptor::EstablishPointerSection(const Descriptor &source,
     const SubscriptValue *stride) {
   *this = source;
   raw_.attribute = CFI_attribute_pointer;
+  SetAllocIdx(source.GetAllocIdx());
   int newRank{raw_.rank};
   for (int j{0}; j < raw_.rank; ++j) {
     if (!stride || stride[j] == 0) {
@@ -242,6 +243,9 @@ RT_API_ATTRS bool Descriptor::EstablishPointerSection(const Descriptor &source,
     }
   }
   raw_.rank = newRank;
+  if (CFI_section(&raw_, &source.raw_, lower, upper, stride) != CFI_SUCCESS) {
+    return false;
+  }
   if (const auto *sourceAddendum = source.Addendum()) {
     if (auto *addendum{Addendum()}) {
       *addendum = *sourceAddendum;
@@ -249,7 +253,7 @@ RT_API_ATTRS bool Descriptor::EstablishPointerSection(const Descriptor &source,
       return false;
     }
   }
-  return CFI_section(&raw_, &source.raw_, lower, upper, stride) == CFI_SUCCESS;
+  return true;
 }
 
 RT_API_ATTRS void Descriptor::ApplyMold(
diff --git a/flang-rt/lib/runtime/io-stmt.cpp b/flang-rt/lib/runtime/io-stmt.cpp
index 36bffd41aa1d6..af44a9d6f2722 100644
--- a/flang-rt/lib/runtime/io-stmt.cpp
+++ b/flang-rt/lib/runtime/io-stmt.cpp
@@ -1078,6 +1078,22 @@ bool ChildFormattedIoStatementState<DIR, CHAR>::AdvanceRecord(int n) {
 #endif
 }
 
+template <Direction DIR>
+ChildListIoStatementState<DIR>::ChildListIoStatementState(
+    ChildIo &child, const char *sourceFile, int sourceLine)
+    : ChildIoStatementState<DIR>{child, sourceFile, sourceLine} {
+#if !defined(RT_DEVICE_AVOID_RECURSION)
+  if constexpr (DIR == Direction::Input) {
+    if (auto *listInput{child.parent()
+                .get_if<ListDirectedStatementState<Direction::Input>>()}) {
+      this->inNamelistSequence_ = listInput->inNamelistSequence();
+    }
+  }
+#else
+  this->ReportUnsupportedChildIo();
+#endif
+}
+
 template <Direction DIR>
 bool ChildUnformattedIoStatementState<DIR>::Receive(
     char *data, std::size_t bytes, std::size_t elementBytes) {
diff --git a/flang-rt/lib/runtime/namelist.cpp b/flang-rt/lib/runtime/namelist.cpp
index 2325ca18ba7aa..4a2174606e716 100644
--- a/flang-rt/lib/runtime/namelist.cpp
+++ b/flang-rt/lib/runtime/namelist.cpp
@@ -268,6 +268,11 @@ static RT_API_ATTRS void StorageSequenceExtension(
                 ? source.GetDimension(0).ByteStride()
                 : static_cast<SubscriptValue>(source.ElementBytes())};
         stride != 0) {
+      common::optional<DescriptorAddendum> savedAddendum;
+      if (const DescriptorAddendum *addendum{desc.Addendum()}) {
+        // Preserve a copy of the addendum, if any, before clobbering it
+        savedAddendum.emplace(*addendum);
+      }
       desc.raw().attribute = CFI_attribute_pointer;
       desc.raw().rank = 1;
       desc.GetDimension(0)
@@ -275,6 +280,9 @@ static RT_API_ATTRS void StorageSequenceExtension(
               source.Elements() -
                   ((source.OffsetElement() - desc.OffsetElement()) / stride))
           .SetByteStride(stride);
+      if (savedAddendum) {
+        *desc.Addendum() = *savedAddendum;
+      }
     }
   }
 }



More information about the llvm-commits mailing list