[flang][runtime] Fix child input bugs under NAMELIST (#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.
This commit is contained in:
Peter Klausler 2025-08-05 13:39:08 -07:00 committed by GitHub
parent cfd1ee781f
commit aec90f2f27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 38 additions and 4 deletions

View File

@ -101,6 +101,9 @@ public:
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 {

View File

@ -461,6 +461,9 @@ public:
inNamelistSequence_ = inNamelistSequence;
}
protected:
bool inNamelistSequence_{false};
private:
int remaining_{0}; // for "r*" repetition
Fortran::common::optional<SavedPosition> repeatPosition_;
@ -468,7 +471,6 @@ private:
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();
};

View File

@ -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();
}

View File

@ -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(

View File

@ -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) {

View File

@ -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;
}
}
}
}