Skip to content

Commit 0d0bd3e

Browse files
authored
[flang] Deep copy nested allocatable components in transformational (#81736)
Spread, reshape, pack, and other transformational intrinsic runtimes are using `CopyElement` utility to copy elements. This utility was dealing with deep copies, but only when the allocatable components where "immediate" components of the type being copied. If the allocatable components were nested inside a nonpointer/nonallocatable component, they were not deep copied, leading to bugs later when manipulating the value (or double free when applying #81117). Visit data components with allocatable components (using the noDestructionNeeded flag to avoid expensive and useless type visit when there are no such components).
1 parent 5f6e0f3 commit 0d0bd3e

File tree

2 files changed

+27
-12
lines changed

2 files changed

+27
-12
lines changed

flang/runtime/copy.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ RT_API_ATTRS void CopyElement(const Descriptor &to, const SubscriptValue toAt[],
2020
const Descriptor &from, const SubscriptValue fromAt[],
2121
Terminator &terminator) {
2222
char *toPtr{to.Element<char>(toAt)};
23-
const char *fromPtr{from.Element<const char>(fromAt)};
23+
char *fromPtr{from.Element<char>(fromAt)};
2424
RUNTIME_CHECK(terminator, to.ElementBytes() == from.ElementBytes());
2525
std::memcpy(toPtr, fromPtr, to.ElementBytes());
26+
// Deep copy allocatable and automatic components if any.
2627
if (const auto *addendum{to.Addendum()}) {
27-
if (const auto *derived{addendum->derivedType()}) {
28+
if (const auto *derived{addendum->derivedType()};
29+
derived && !derived->noDestructionNeeded()) {
2830
RUNTIME_CHECK(terminator,
2931
from.Addendum() && derived == from.Addendum()->derivedType());
3032
const Descriptor &componentDesc{derived->component()};
@@ -43,6 +45,26 @@ RT_API_ATTRS void CopyElement(const Descriptor &to, const SubscriptValue toAt[],
4345
fromPtr + component->offset())};
4446
CopyArray(toDesc, fromDesc, terminator);
4547
}
48+
} else if (component->genre() == typeInfo::Component::Genre::Data &&
49+
component->derivedType() &&
50+
!component->derivedType()->noDestructionNeeded()) {
51+
SubscriptValue extents[maxRank];
52+
const typeInfo::Value *bounds{component->bounds()};
53+
for (int dim{0}; dim < component->rank(); ++dim) {
54+
SubscriptValue lb{bounds[2 * dim].GetValue(&to).value_or(0)};
55+
SubscriptValue ub{bounds[2 * dim + 1].GetValue(&to).value_or(0)};
56+
extents[dim] = ub >= lb ? ub - lb + 1 : 0;
57+
}
58+
const typeInfo::DerivedType &compType{*component->derivedType()};
59+
StaticDescriptor<maxRank, true, 0> toStaticDescriptor;
60+
Descriptor &toCompDesc{toStaticDescriptor.descriptor()};
61+
toCompDesc.Establish(compType, toPtr + component->offset(),
62+
component->rank(), extents);
63+
StaticDescriptor<maxRank, true, 0> fromStaticDescriptor;
64+
Descriptor &fromCompDesc{fromStaticDescriptor.descriptor()};
65+
fromCompDesc.Establish(compType, fromPtr + component->offset(),
66+
component->rank(), extents);
67+
CopyArray(toCompDesc, fromCompDesc, terminator);
4668
}
4769
}
4870
}

flang/runtime/derived.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,9 @@ RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize,
340340
RT_API_ATTRS bool HasDynamicComponent(const Descriptor &descriptor) {
341341
if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
342342
if (const auto *derived = addendum->derivedType()) {
343-
const Descriptor &componentDesc{derived->component()};
344-
std::size_t myComponents{componentDesc.Elements()};
345-
for (std::size_t k{0}; k < myComponents; ++k) {
346-
const auto &comp{
347-
*componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
348-
if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
349-
comp.genre() == typeInfo::Component::Genre::Automatic) {
350-
return true;
351-
}
352-
}
343+
// Destruction is needed if and only if there are direct or indirect
344+
// allocatable or automatic components.
345+
return !derived->noDestructionNeeded();
353346
}
354347
}
355348
return false;

0 commit comments

Comments
 (0)