From bf684e0f2f97c56cdea9e36b6dacde48dc5cc269 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Wed, 17 Sep 2025 09:14:32 -0700 Subject: [PATCH] [flang][runtime] Disable namelist storage sequence input when defined (#158708) The runtime supports a near-universal extension to namelist input that allows reading a sequence of values into a storage sequence beginning at an array element, e.g. &NML A(2)=1. 2. 3. / . Disable this extension when the type of the array has a defined formatted READ subroutine defined. That defined input procedure may itself not be using list-directed input, and might not notice a following slash or new input item name as such. Fixes https://github.com/llvm/llvm-project/issues/158496. --- flang-rt/lib/runtime/namelist.cpp | 36 +++++++++++++++++++++++++++---- flang/docs/Extensions.md | 3 +++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/flang-rt/lib/runtime/namelist.cpp b/flang-rt/lib/runtime/namelist.cpp index 79dbe4b82292..47b16433e631 100644 --- a/flang-rt/lib/runtime/namelist.cpp +++ b/flang-rt/lib/runtime/namelist.cpp @@ -258,13 +258,40 @@ static RT_API_ATTRS bool HandleSubscripts(IoStatementState &io, return false; } -static RT_API_ATTRS void StorageSequenceExtension( - Descriptor &desc, const Descriptor &source) { +static RT_API_ATTRS bool HasDefinedIoSubroutine(common::DefinedIo definedIo, + typeInfo::SpecialBinding::Which specialBinding, + const typeInfo::DerivedType *derivedType, + const NonTbpDefinedIoTable *table) { + for (; derivedType; derivedType = derivedType->GetParentType()) { + if ((table && table->Find(*derivedType, definedIo) != nullptr) || + derivedType->FindSpecialBinding(specialBinding)) { + return true; + } + } + return false; +} + +static RT_API_ATTRS bool HasDefinedIoSubroutine(common::DefinedIo definedIo, + typeInfo::SpecialBinding::Which specialBinding, + const Descriptor &descriptor, const NonTbpDefinedIoTable *table) { + const DescriptorAddendum *addendum{descriptor.Addendum()}; + return addendum && + HasDefinedIoSubroutine( + definedIo, specialBinding, addendum->derivedType(), table); +} + +static RT_API_ATTRS void StorageSequenceExtension(Descriptor &desc, + const Descriptor &source, const io::NonTbpDefinedIoTable *table) { // Support the near-universal extension of NAMELIST input into a // designatable storage sequence identified by its initial scalar array // element. For example, treat "A(1) = 1. 2. 3." as if it had been // "A(1:) = 1. 2. 3.". - if (desc.rank() == 0 && (source.rank() == 1 || source.IsContiguous())) { + // (But don't do this for derived types with defined formatted READs, + // since they might do non-list-directed input that won't stop at the + // next namelist input item name.) + if (desc.rank() == 0 && (source.rank() == 1 || source.IsContiguous()) && + !HasDefinedIoSubroutine(common::DefinedIo::ReadFormatted, + typeInfo::SpecialBinding::Which::ReadFormatted, desc, table)) { if (auto stride{source.rank() == 1 ? source.GetDimension(0).ByteStride() : static_cast(source.ElementBytes())}; @@ -561,7 +588,8 @@ bool IODEF(InputNamelist)(Cookie cookie, const NamelistGroup &group) { next = io.GetCurrentChar(byteCount); } while (next && (*next == '(' || *next == '%')); if (lastSubscriptDescriptor) { - StorageSequenceExtension(*lastSubscriptDescriptor, *lastSubscriptBase); + StorageSequenceExtension(*lastSubscriptDescriptor, *lastSubscriptBase, + group.nonTbpDefinedIo); } } // Skip the '=' diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md index cf528b8231d5..c442a9cd6859 100644 --- a/flang/docs/Extensions.md +++ b/flang/docs/Extensions.md @@ -930,3 +930,6 @@ print *, [(j,j=1,10)] or contiguous array can be used as the initial element of a storage sequence. For example, "&GRP A(1)=1. 2. 3./" is treated as if had been "&GRP A(1:)=1. 2. 3./". + This extension is necessarily disabled when the type of the array + has an accessible defined formatted READ subroutine. +