Skip to content

Commit 5f6e0f3

Browse files
authored
[flang][runtime] Destroy nested allocatable components (#81117)
The runtime was currently only deallocating the direct allocatable components, which caused leaks when there are allocatable components nested in the direct components. Update Destroy to recursively destroy components. Also call Destroy from Assign to deallocate nested allocatable components before doing the assignment as required by F2018 9.7.3.2 point 7. This lack of deallocation was visible if the nested components had user defined assignment "observing" the allocation state.
1 parent 28d4385 commit 5f6e0f3

File tree

2 files changed

+44
-19
lines changed

2 files changed

+44
-19
lines changed

flang/runtime/assign.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ RT_API_ATTRS static void Assign(
320320
if ((flags & NeedFinalization) && toDerived) {
321321
Finalize(to, *toDerived, &terminator);
322322
flags &= ~NeedFinalization;
323+
} else if (toDerived && !toDerived->noDestructionNeeded()) {
324+
Destroy(to, /*finalize=*/false, *toDerived, &terminator);
323325
}
324326
} else {
325327
to.Destroy((flags & NeedFinalization) != 0, /*destroyPointers=*/false,
@@ -389,6 +391,8 @@ RT_API_ATTRS static void Assign(
389391
// The target is first finalized if still necessary (7.5.6.3(1))
390392
if (flags & NeedFinalization) {
391393
Finalize(to, *updatedToDerived, &terminator);
394+
} else if (updatedToDerived && !updatedToDerived->noDestructionNeeded()) {
395+
Destroy(to, /*finalize=*/false, *updatedToDerived, &terminator);
392396
}
393397
// Copy the data components (incl. the parent) first.
394398
const Descriptor &componentDesc{updatedToDerived->component()};

flang/runtime/derived.cpp

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ namespace Fortran::runtime {
1717

1818
RT_OFFLOAD_API_GROUP_BEGIN
1919

20+
// Fill "extents" array with the extents of component "comp" from derived type
21+
// instance "derivedInstance".
22+
static RT_API_ATTRS void GetComponentExtents(SubscriptValue (&extents)[maxRank],
23+
const typeInfo::Component &comp, const Descriptor &derivedInstance) {
24+
const typeInfo::Value *bounds{comp.bounds()};
25+
for (int dim{0}; dim < comp.rank(); ++dim) {
26+
SubscriptValue lb{bounds[2 * dim].GetValue(&derivedInstance).value_or(0)};
27+
SubscriptValue ub{
28+
bounds[2 * dim + 1].GetValue(&derivedInstance).value_or(0)};
29+
extents[dim] = ub >= lb ? ub - lb + 1 : 0;
30+
}
31+
}
32+
2033
RT_API_ATTRS int Initialize(const Descriptor &instance,
2134
const typeInfo::DerivedType &derived, Terminator &terminator, bool hasStat,
2235
const Descriptor *errMsg) {
@@ -77,22 +90,15 @@ RT_API_ATTRS int Initialize(const Descriptor &instance,
7790
comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) {
7891
// Default initialization of non-pointer non-allocatable/automatic
7992
// data component. Handles parent component's elements. Recursive.
80-
SubscriptValue extent[maxRank];
81-
const typeInfo::Value *bounds{comp.bounds()};
82-
for (int dim{0}; dim < comp.rank(); ++dim) {
83-
typeInfo::TypeParameterValue lb{
84-
bounds[2 * dim].GetValue(&instance).value_or(0)};
85-
typeInfo::TypeParameterValue ub{
86-
bounds[2 * dim + 1].GetValue(&instance).value_or(0)};
87-
extent[dim] = ub >= lb ? ub - lb + 1 : 0;
88-
}
93+
SubscriptValue extents[maxRank];
94+
GetComponentExtents(extents, comp, instance);
8995
StaticDescriptor<maxRank, true, 0> staticDescriptor;
9096
Descriptor &compDesc{staticDescriptor.descriptor()};
9197
const typeInfo::DerivedType &compType{*comp.derivedType()};
9298
for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
9399
compDesc.Establish(compType,
94100
instance.ElementComponent<char>(at, comp.offset()), comp.rank(),
95-
extent);
101+
extents);
96102
stat = Initialize(compDesc, compType, terminator, hasStat, errMsg);
97103
if (stat != StatOk) {
98104
break;
@@ -253,22 +259,16 @@ RT_API_ATTRS void Finalize(const Descriptor &descriptor,
253259
}
254260
} else if (comp.genre() == typeInfo::Component::Genre::Data &&
255261
comp.derivedType() && !comp.derivedType()->noFinalizationNeeded()) {
256-
SubscriptValue extent[maxRank];
257-
const typeInfo::Value *bounds{comp.bounds()};
258-
for (int dim{0}; dim < comp.rank(); ++dim) {
259-
SubscriptValue lb{bounds[2 * dim].GetValue(&descriptor).value_or(0)};
260-
SubscriptValue ub{
261-
bounds[2 * dim + 1].GetValue(&descriptor).value_or(0)};
262-
extent[dim] = ub >= lb ? ub - lb + 1 : 0;
263-
}
262+
SubscriptValue extents[maxRank];
263+
GetComponentExtents(extents, comp, descriptor);
264264
StaticDescriptor<maxRank, true, 0> staticDescriptor;
265265
Descriptor &compDesc{staticDescriptor.descriptor()};
266266
const typeInfo::DerivedType &compType{*comp.derivedType()};
267267
for (std::size_t j{0}; j++ < elements;
268268
descriptor.IncrementSubscripts(at)) {
269269
compDesc.Establish(compType,
270270
descriptor.ElementComponent<char>(at, comp.offset()), comp.rank(),
271-
extent);
271+
extents);
272272
Finalize(compDesc, compType, terminator);
273273
}
274274
}
@@ -296,6 +296,8 @@ RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize,
296296
if (finalize && !derived.noFinalizationNeeded()) {
297297
Finalize(descriptor, derived, terminator);
298298
}
299+
// Deallocate all direct and indirect allocatable and automatic components.
300+
// Contrary to finalization, the order of deallocation does not matter.
299301
const Descriptor &componentDesc{derived.component()};
300302
std::size_t myComponents{componentDesc.Elements()};
301303
std::size_t elements{descriptor.Elements()};
@@ -304,14 +306,33 @@ RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize,
304306
for (std::size_t k{0}; k < myComponents; ++k) {
305307
const auto &comp{
306308
*componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
309+
const bool destroyComp{
310+
comp.derivedType() && !comp.derivedType()->noDestructionNeeded()};
307311
if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
308312
comp.genre() == typeInfo::Component::Genre::Automatic) {
309313
for (std::size_t j{0}; j < elements; ++j) {
310314
Descriptor *d{
311315
descriptor.ElementComponent<Descriptor>(at, comp.offset())};
316+
if (destroyComp) {
317+
Destroy(*d, /*finalize=*/false, *comp.derivedType(), terminator);
318+
}
312319
d->Deallocate();
313320
descriptor.IncrementSubscripts(at);
314321
}
322+
} else if (destroyComp &&
323+
comp.genre() == typeInfo::Component::Genre::Data) {
324+
SubscriptValue extents[maxRank];
325+
GetComponentExtents(extents, comp, descriptor);
326+
StaticDescriptor<maxRank, true, 0> staticDescriptor;
327+
Descriptor &compDesc{staticDescriptor.descriptor()};
328+
const typeInfo::DerivedType &compType{*comp.derivedType()};
329+
for (std::size_t j{0}; j++ < elements;
330+
descriptor.IncrementSubscripts(at)) {
331+
compDesc.Establish(compType,
332+
descriptor.ElementComponent<char>(at, comp.offset()), comp.rank(),
333+
extents);
334+
Destroy(compDesc, /*finalize=*/false, *comp.derivedType(), terminator);
335+
}
315336
}
316337
}
317338
}

0 commit comments

Comments
 (0)