xref: /llvm-project/flang/runtime/derived.cpp (revision 5130a4ea121fa74b0fe9a0c9a44ede651f94f93a)
14fede8bcSpeter klausler //===-- runtime/derived.cpp -----------------------------------------------===//
24fede8bcSpeter klausler //
34fede8bcSpeter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44fede8bcSpeter klausler // See https://llvm.org/LICENSE.txt for license information.
54fede8bcSpeter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64fede8bcSpeter klausler //
74fede8bcSpeter klausler //===----------------------------------------------------------------------===//
84fede8bcSpeter klausler 
94fede8bcSpeter klausler #include "derived.h"
10a48e4168Speter klausler #include "stat.h"
11a48e4168Speter klausler #include "terminator.h"
12b21c24c3SPeter Klausler #include "tools.h"
134fede8bcSpeter klausler #include "type-info.h"
14830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
154fede8bcSpeter klausler 
164fede8bcSpeter klausler namespace Fortran::runtime {
174fede8bcSpeter klausler 
188b953fddSSlava Zakharin RT_OFFLOAD_API_GROUP_BEGIN
198b953fddSSlava Zakharin 
205f6e0f35SjeanPerier // Fill "extents" array with the extents of component "comp" from derived type
215f6e0f35SjeanPerier // instance "derivedInstance".
225f6e0f35SjeanPerier static RT_API_ATTRS void GetComponentExtents(SubscriptValue (&extents)[maxRank],
235f6e0f35SjeanPerier     const typeInfo::Component &comp, const Descriptor &derivedInstance) {
245f6e0f35SjeanPerier   const typeInfo::Value *bounds{comp.bounds()};
255f6e0f35SjeanPerier   for (int dim{0}; dim < comp.rank(); ++dim) {
266db2465cSserge-sans-paille     auto lb{bounds[2 * dim].GetValue(&derivedInstance).value_or(0)};
276db2465cSserge-sans-paille     auto ub{bounds[2 * dim + 1].GetValue(&derivedInstance).value_or(0)};
286db2465cSserge-sans-paille     extents[dim] = ub >= lb ? static_cast<SubscriptValue>(ub - lb + 1) : 0;
295f6e0f35SjeanPerier   }
305f6e0f35SjeanPerier }
315f6e0f35SjeanPerier 
328b953fddSSlava Zakharin RT_API_ATTRS int Initialize(const Descriptor &instance,
338b953fddSSlava Zakharin     const typeInfo::DerivedType &derived, Terminator &terminator, bool hasStat,
348b953fddSSlava Zakharin     const Descriptor *errMsg) {
35a48e4168Speter klausler   const Descriptor &componentDesc{derived.component()};
36a48e4168Speter klausler   std::size_t elements{instance.Elements()};
37a48e4168Speter klausler   int stat{StatOk};
38392173daSPeter Klausler   // Initialize data components in each element; the per-element iterations
39392173daSPeter Klausler   // constitute the inner loops, not the outer ones
40a48e4168Speter klausler   std::size_t myComponents{componentDesc.Elements()};
41a48e4168Speter klausler   for (std::size_t k{0}; k < myComponents; ++k) {
42a48e4168Speter klausler     const auto &comp{
43a48e4168Speter klausler         *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
44e3d6a3acSjeanPerier     SubscriptValue at[maxRank];
45e3d6a3acSjeanPerier     instance.GetLowerBounds(at);
46a48e4168Speter klausler     if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
47a48e4168Speter klausler         comp.genre() == typeInfo::Component::Genre::Automatic) {
48e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
49e3d6a3acSjeanPerier         Descriptor &allocDesc{
50e3d6a3acSjeanPerier             *instance.ElementComponent<Descriptor>(at, comp.offset())};
51a48e4168Speter klausler         comp.EstablishDescriptor(allocDesc, instance, terminator);
52a48e4168Speter klausler         allocDesc.raw().attribute = CFI_attribute_allocatable;
53a48e4168Speter klausler         if (comp.genre() == typeInfo::Component::Genre::Automatic) {
54a48e4168Speter klausler           stat = ReturnError(terminator, allocDesc.Allocate(), errMsg, hasStat);
55a48e4168Speter klausler           if (stat == StatOk) {
56392173daSPeter Klausler             if (const DescriptorAddendum * addendum{allocDesc.Addendum()}) {
57392173daSPeter Klausler               if (const auto *derived{addendum->derivedType()}) {
58392173daSPeter Klausler                 if (!derived->noInitializationNeeded()) {
59392173daSPeter Klausler                   stat = Initialize(
60392173daSPeter Klausler                       allocDesc, *derived, terminator, hasStat, errMsg);
61392173daSPeter Klausler                 }
62392173daSPeter Klausler               }
63392173daSPeter Klausler             }
64a48e4168Speter klausler           }
65a48e4168Speter klausler           if (stat != StatOk) {
66a48e4168Speter klausler             break;
67a48e4168Speter klausler           }
68a48e4168Speter klausler         }
69a48e4168Speter klausler       }
70a48e4168Speter klausler     } else if (const void *init{comp.initialization()}) {
71a48e4168Speter klausler       // Explicit initialization of data pointers and
72a48e4168Speter klausler       // non-allocatable non-automatic components
73a48e4168Speter klausler       std::size_t bytes{comp.SizeInBytes(instance)};
74e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
75e3d6a3acSjeanPerier         char *ptr{instance.ElementComponent<char>(at, comp.offset())};
76a48e4168Speter klausler         std::memcpy(ptr, init, bytes);
77a48e4168Speter klausler       }
7827cf6ba1SPeter Klausler     } else if (comp.genre() == typeInfo::Component::Genre::Pointer) {
7927cf6ba1SPeter Klausler       // Data pointers without explicit initialization are established
8027cf6ba1SPeter Klausler       // so that they are valid right-hand side targets of pointer
8127cf6ba1SPeter Klausler       // assignment statements.
82e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
83e3d6a3acSjeanPerier         Descriptor &ptrDesc{
84e3d6a3acSjeanPerier             *instance.ElementComponent<Descriptor>(at, comp.offset())};
8527cf6ba1SPeter Klausler         comp.EstablishDescriptor(ptrDesc, instance, terminator);
8627cf6ba1SPeter Klausler         ptrDesc.raw().attribute = CFI_attribute_pointer;
8727cf6ba1SPeter Klausler       }
88a48e4168Speter klausler     } else if (comp.genre() == typeInfo::Component::Genre::Data &&
89a48e4168Speter klausler         comp.derivedType() && !comp.derivedType()->noInitializationNeeded()) {
90a48e4168Speter klausler       // Default initialization of non-pointer non-allocatable/automatic
91a48e4168Speter klausler       // data component.  Handles parent component's elements.  Recursive.
925f6e0f35SjeanPerier       SubscriptValue extents[maxRank];
935f6e0f35SjeanPerier       GetComponentExtents(extents, comp, instance);
94a48e4168Speter klausler       StaticDescriptor<maxRank, true, 0> staticDescriptor;
95a48e4168Speter klausler       Descriptor &compDesc{staticDescriptor.descriptor()};
96a48e4168Speter klausler       const typeInfo::DerivedType &compType{*comp.derivedType()};
97e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
98a48e4168Speter klausler         compDesc.Establish(compType,
99e3d6a3acSjeanPerier             instance.ElementComponent<char>(at, comp.offset()), comp.rank(),
1005f6e0f35SjeanPerier             extents);
101a48e4168Speter klausler         stat = Initialize(compDesc, compType, terminator, hasStat, errMsg);
102a48e4168Speter klausler         if (stat != StatOk) {
103a48e4168Speter klausler           break;
104a48e4168Speter klausler         }
105a48e4168Speter klausler       }
106a48e4168Speter klausler     }
107a48e4168Speter klausler   }
108a48e4168Speter klausler   // Initialize procedure pointer components in each element
109a48e4168Speter klausler   const Descriptor &procPtrDesc{derived.procPtr()};
110a48e4168Speter klausler   std::size_t myProcPtrs{procPtrDesc.Elements()};
111a48e4168Speter klausler   for (std::size_t k{0}; k < myProcPtrs; ++k) {
112a48e4168Speter klausler     const auto &comp{
113a48e4168Speter klausler         *procPtrDesc.ZeroBasedIndexedElement<typeInfo::ProcPtrComponent>(k)};
114e3d6a3acSjeanPerier     SubscriptValue at[maxRank];
115e3d6a3acSjeanPerier     instance.GetLowerBounds(at);
116e3d6a3acSjeanPerier     for (std::size_t j{0}; j++ < elements; instance.IncrementSubscripts(at)) {
117e3d6a3acSjeanPerier       auto &pptr{*instance.ElementComponent<typeInfo::ProcedurePointer>(
118e3d6a3acSjeanPerier           at, comp.offset)};
119a48e4168Speter klausler       pptr = comp.procInitialization;
120a48e4168Speter klausler     }
121a48e4168Speter klausler   }
122a48e4168Speter klausler   return stat;
123a48e4168Speter klausler }
124a48e4168Speter klausler 
1251fcb6a97SLeandro Lupori RT_API_ATTRS int InitializeClone(const Descriptor &clone,
1261fcb6a97SLeandro Lupori     const Descriptor &orig, const typeInfo::DerivedType &derived,
1271fcb6a97SLeandro Lupori     Terminator &terminator, bool hasStat, const Descriptor *errMsg) {
1281fcb6a97SLeandro Lupori   const Descriptor &componentDesc{derived.component()};
1291fcb6a97SLeandro Lupori   std::size_t elements{orig.Elements()};
1301fcb6a97SLeandro Lupori   int stat{StatOk};
1311fcb6a97SLeandro Lupori 
132*5130a4eaSLeandro Lupori   // Skip pointers and unallocated variables.
133*5130a4eaSLeandro Lupori   if (orig.IsPointer() || !orig.IsAllocated()) {
134*5130a4eaSLeandro Lupori     return stat;
135*5130a4eaSLeandro Lupori   }
1361fcb6a97SLeandro Lupori   // Initialize each data component.
1371fcb6a97SLeandro Lupori   std::size_t components{componentDesc.Elements()};
1381fcb6a97SLeandro Lupori   for (std::size_t i{0}; i < components; ++i) {
1391fcb6a97SLeandro Lupori     const typeInfo::Component &comp{
1401fcb6a97SLeandro Lupori         *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(i)};
1411fcb6a97SLeandro Lupori     SubscriptValue at[maxRank];
1421fcb6a97SLeandro Lupori     orig.GetLowerBounds(at);
1431fcb6a97SLeandro Lupori     // Allocate allocatable components that are also allocated in the original
1441fcb6a97SLeandro Lupori     // object.
1451fcb6a97SLeandro Lupori     if (comp.genre() == typeInfo::Component::Genre::Allocatable) {
1461fcb6a97SLeandro Lupori       // Initialize each element.
1471fcb6a97SLeandro Lupori       for (std::size_t j{0}; j < elements; ++j, orig.IncrementSubscripts(at)) {
1481fcb6a97SLeandro Lupori         Descriptor &origDesc{
1491fcb6a97SLeandro Lupori             *orig.ElementComponent<Descriptor>(at, comp.offset())};
1501fcb6a97SLeandro Lupori         Descriptor &cloneDesc{
1511fcb6a97SLeandro Lupori             *clone.ElementComponent<Descriptor>(at, comp.offset())};
1521fcb6a97SLeandro Lupori         if (origDesc.IsAllocated()) {
1531fcb6a97SLeandro Lupori           cloneDesc.ApplyMold(origDesc, origDesc.rank());
1541fcb6a97SLeandro Lupori           stat = ReturnError(terminator, cloneDesc.Allocate(), errMsg, hasStat);
1551fcb6a97SLeandro Lupori           if (stat == StatOk) {
1561fcb6a97SLeandro Lupori             if (const DescriptorAddendum * addendum{cloneDesc.Addendum()}) {
1571fcb6a97SLeandro Lupori               if (const typeInfo::DerivedType *
1581fcb6a97SLeandro Lupori                   derived{addendum->derivedType()}) {
1591fcb6a97SLeandro Lupori                 if (!derived->noInitializationNeeded()) {
1601fcb6a97SLeandro Lupori                   // Perform default initialization for the allocated element.
1611fcb6a97SLeandro Lupori                   stat = Initialize(
1621fcb6a97SLeandro Lupori                       cloneDesc, *derived, terminator, hasStat, errMsg);
1631fcb6a97SLeandro Lupori                 }
1641fcb6a97SLeandro Lupori                 // Initialize derived type's allocatables.
1651fcb6a97SLeandro Lupori                 if (stat == StatOk) {
1661fcb6a97SLeandro Lupori                   stat = InitializeClone(cloneDesc, origDesc, *derived,
1671fcb6a97SLeandro Lupori                       terminator, hasStat, errMsg);
1681fcb6a97SLeandro Lupori                 }
1691fcb6a97SLeandro Lupori               }
1701fcb6a97SLeandro Lupori             }
1711fcb6a97SLeandro Lupori           }
1721fcb6a97SLeandro Lupori         }
1731fcb6a97SLeandro Lupori         if (stat != StatOk) {
1741fcb6a97SLeandro Lupori           break;
1751fcb6a97SLeandro Lupori         }
1761fcb6a97SLeandro Lupori       }
1771fcb6a97SLeandro Lupori     } else if (comp.genre() == typeInfo::Component::Genre::Data &&
1781fcb6a97SLeandro Lupori         comp.derivedType()) {
1791fcb6a97SLeandro Lupori       // Handle nested derived types.
1801fcb6a97SLeandro Lupori       const typeInfo::DerivedType &compType{*comp.derivedType()};
1811fcb6a97SLeandro Lupori       SubscriptValue extents[maxRank];
1821fcb6a97SLeandro Lupori       GetComponentExtents(extents, comp, orig);
1831fcb6a97SLeandro Lupori       // Data components don't have descriptors, allocate them.
1841fcb6a97SLeandro Lupori       StaticDescriptor<maxRank, true, 0> origStaticDesc;
1851fcb6a97SLeandro Lupori       StaticDescriptor<maxRank, true, 0> cloneStaticDesc;
1861fcb6a97SLeandro Lupori       Descriptor &origDesc{origStaticDesc.descriptor()};
1871fcb6a97SLeandro Lupori       Descriptor &cloneDesc{cloneStaticDesc.descriptor()};
1881fcb6a97SLeandro Lupori       // Initialize each element.
1891fcb6a97SLeandro Lupori       for (std::size_t j{0}; j < elements; ++j, orig.IncrementSubscripts(at)) {
1901fcb6a97SLeandro Lupori         origDesc.Establish(compType,
1911fcb6a97SLeandro Lupori             orig.ElementComponent<char>(at, comp.offset()), comp.rank(),
1921fcb6a97SLeandro Lupori             extents);
1931fcb6a97SLeandro Lupori         cloneDesc.Establish(compType,
1941fcb6a97SLeandro Lupori             clone.ElementComponent<char>(at, comp.offset()), comp.rank(),
1951fcb6a97SLeandro Lupori             extents);
1961fcb6a97SLeandro Lupori         stat = InitializeClone(
1971fcb6a97SLeandro Lupori             cloneDesc, origDesc, compType, terminator, hasStat, errMsg);
1981fcb6a97SLeandro Lupori         if (stat != StatOk) {
1991fcb6a97SLeandro Lupori           break;
2001fcb6a97SLeandro Lupori         }
2011fcb6a97SLeandro Lupori       }
2021fcb6a97SLeandro Lupori     }
2031fcb6a97SLeandro Lupori   }
2041fcb6a97SLeandro Lupori   return stat;
2051fcb6a97SLeandro Lupori }
2061fcb6a97SLeandro Lupori 
2078b953fddSSlava Zakharin static RT_API_ATTRS const typeInfo::SpecialBinding *FindFinal(
2084fede8bcSpeter klausler     const typeInfo::DerivedType &derived, int rank) {
20965f52904Speter klausler   if (const auto *ranked{derived.FindSpecialBinding(
21065f52904Speter klausler           typeInfo::SpecialBinding::RankFinal(rank))}) {
21165f52904Speter klausler     return ranked;
21265f52904Speter klausler   } else if (const auto *assumed{derived.FindSpecialBinding(
21365f52904Speter klausler                  typeInfo::SpecialBinding::Which::AssumedRankFinal)}) {
21465f52904Speter klausler     return assumed;
21565f52904Speter klausler   } else {
21665f52904Speter klausler     return derived.FindSpecialBinding(
21765f52904Speter klausler         typeInfo::SpecialBinding::Which::ElementalFinal);
2184fede8bcSpeter klausler   }
2194fede8bcSpeter klausler }
2204fede8bcSpeter klausler 
2218b953fddSSlava Zakharin static RT_API_ATTRS void CallFinalSubroutine(const Descriptor &descriptor,
222b21c24c3SPeter Klausler     const typeInfo::DerivedType &derived, Terminator *terminator) {
2234fede8bcSpeter klausler   if (const auto *special{FindFinal(derived, descriptor.rank())}) {
22443fadefbSpeter klausler     if (special->which() == typeInfo::SpecialBinding::Which::ElementalFinal) {
2254fede8bcSpeter klausler       std::size_t elements{descriptor.Elements()};
226e3d6a3acSjeanPerier       SubscriptValue at[maxRank];
227e3d6a3acSjeanPerier       descriptor.GetLowerBounds(at);
228a48e4168Speter klausler       if (special->IsArgDescriptor(0)) {
229a48e4168Speter klausler         StaticDescriptor<maxRank, true, 8 /*?*/> statDesc;
230a48e4168Speter klausler         Descriptor &elemDesc{statDesc.descriptor()};
231a48e4168Speter klausler         elemDesc = descriptor;
232a48e4168Speter klausler         elemDesc.raw().attribute = CFI_attribute_pointer;
233a48e4168Speter klausler         elemDesc.raw().rank = 0;
234a48e4168Speter klausler         auto *p{special->GetProc<void (*)(const Descriptor &)>()};
235e3d6a3acSjeanPerier         for (std::size_t j{0}; j++ < elements;
236e3d6a3acSjeanPerier              descriptor.IncrementSubscripts(at)) {
237e3d6a3acSjeanPerier           elemDesc.set_base_addr(descriptor.Element<char>(at));
238a48e4168Speter klausler           p(elemDesc);
239a48e4168Speter klausler         }
240a48e4168Speter klausler       } else {
241a48e4168Speter klausler         auto *p{special->GetProc<void (*)(char *)>()};
242e3d6a3acSjeanPerier         for (std::size_t j{0}; j++ < elements;
243e3d6a3acSjeanPerier              descriptor.IncrementSubscripts(at)) {
244e3d6a3acSjeanPerier           p(descriptor.Element<char>(at));
2454fede8bcSpeter klausler         }
246a48e4168Speter klausler       }
247b21c24c3SPeter Klausler     } else {
248b21c24c3SPeter Klausler       StaticDescriptor<maxRank, true, 10> statDesc;
249b21c24c3SPeter Klausler       Descriptor &copy{statDesc.descriptor()};
250b21c24c3SPeter Klausler       const Descriptor *argDescriptor{&descriptor};
251b21c24c3SPeter Klausler       if (descriptor.rank() > 0 && special->IsArgContiguous(0) &&
252b21c24c3SPeter Klausler           !descriptor.IsContiguous()) {
253b21c24c3SPeter Klausler         // The FINAL subroutine demands a contiguous array argument, but
254b21c24c3SPeter Klausler         // this INTENT(OUT) or intrinsic assignment LHS isn't contiguous.
255b21c24c3SPeter Klausler         // Finalize a shallow copy of the data.
256b21c24c3SPeter Klausler         copy = descriptor;
257b21c24c3SPeter Klausler         copy.set_base_addr(nullptr);
258b21c24c3SPeter Klausler         copy.raw().attribute = CFI_attribute_allocatable;
259b21c24c3SPeter Klausler         Terminator stubTerminator{"CallFinalProcedure() in Fortran runtime", 0};
260b21c24c3SPeter Klausler         RUNTIME_CHECK(terminator ? *terminator : stubTerminator,
261b21c24c3SPeter Klausler             copy.Allocate() == CFI_SUCCESS);
262b21c24c3SPeter Klausler         ShallowCopyDiscontiguousToContiguous(copy, descriptor);
263b21c24c3SPeter Klausler         argDescriptor = &copy;
264b21c24c3SPeter Klausler       }
265b21c24c3SPeter Klausler       if (special->IsArgDescriptor(0)) {
266a48e4168Speter klausler         StaticDescriptor<maxRank, true, 8 /*?*/> statDesc;
267a48e4168Speter klausler         Descriptor &tmpDesc{statDesc.descriptor()};
268b21c24c3SPeter Klausler         tmpDesc = *argDescriptor;
269a48e4168Speter klausler         tmpDesc.raw().attribute = CFI_attribute_pointer;
270a48e4168Speter klausler         tmpDesc.Addendum()->set_derivedType(&derived);
27143fadefbSpeter klausler         auto *p{special->GetProc<void (*)(const Descriptor &)>()};
272a48e4168Speter klausler         p(tmpDesc);
2734fede8bcSpeter klausler       } else {
27443fadefbSpeter klausler         auto *p{special->GetProc<void (*)(char *)>()};
275b21c24c3SPeter Klausler         p(argDescriptor->OffsetElement<char>());
276b21c24c3SPeter Klausler       }
277b21c24c3SPeter Klausler       if (argDescriptor == &copy) {
278b21c24c3SPeter Klausler         ShallowCopyContiguousToDiscontiguous(descriptor, copy);
279b21c24c3SPeter Klausler         copy.Deallocate();
280b21c24c3SPeter Klausler       }
2814fede8bcSpeter klausler     }
2824fede8bcSpeter klausler   }
2834fede8bcSpeter klausler }
2844fede8bcSpeter klausler 
28565f52904Speter klausler // Fortran 2018 subclause 7.5.6.2
2868b953fddSSlava Zakharin RT_API_ATTRS void Finalize(const Descriptor &descriptor,
287b21c24c3SPeter Klausler     const typeInfo::DerivedType &derived, Terminator *terminator) {
28865f52904Speter klausler   if (derived.noFinalizationNeeded() || !descriptor.IsAllocated()) {
28965f52904Speter klausler     return;
2904fede8bcSpeter klausler   }
291b21c24c3SPeter Klausler   CallFinalSubroutine(descriptor, derived, terminator);
29265f52904Speter klausler   const auto *parentType{derived.GetParentType()};
29365f52904Speter klausler   bool recurse{parentType && !parentType->noFinalizationNeeded()};
29465f52904Speter klausler   // If there's a finalizable parent component, handle it last, as required
29565f52904Speter klausler   // by the Fortran standard (7.5.6.2), and do so recursively with the same
29665f52904Speter klausler   // descriptor so that the rank is preserved.
29779caf69cSpeter klausler   const Descriptor &componentDesc{derived.component()};
298a48e4168Speter klausler   std::size_t myComponents{componentDesc.Elements()};
2994fede8bcSpeter klausler   std::size_t elements{descriptor.Elements()};
300b21c24c3SPeter Klausler   for (auto k{recurse ? std::size_t{1}
301b21c24c3SPeter Klausler                       /* skip first component, it's the parent */
302a48e4168Speter klausler                       : 0};
303a48e4168Speter klausler        k < myComponents; ++k) {
3044fede8bcSpeter klausler     const auto &comp{
3054fede8bcSpeter klausler         *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
306e3d6a3acSjeanPerier     SubscriptValue at[maxRank];
307e3d6a3acSjeanPerier     descriptor.GetLowerBounds(at);
308efd5cdeeSjeanPerier     if (comp.genre() == typeInfo::Component::Genre::Allocatable &&
309efd5cdeeSjeanPerier         comp.category() == TypeCategory::Derived) {
310efd5cdeeSjeanPerier       // Component may be polymorphic or unlimited polymorphic. Need to use the
311efd5cdeeSjeanPerier       // dynamic type to check whether finalization is needed.
312e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements;
313e3d6a3acSjeanPerier            descriptor.IncrementSubscripts(at)) {
314e3d6a3acSjeanPerier         const Descriptor &compDesc{
315e3d6a3acSjeanPerier             *descriptor.ElementComponent<Descriptor>(at, comp.offset())};
316efd5cdeeSjeanPerier         if (compDesc.IsAllocated()) {
317efd5cdeeSjeanPerier           if (const DescriptorAddendum * addendum{compDesc.Addendum()}) {
318efd5cdeeSjeanPerier             if (const typeInfo::DerivedType *
319efd5cdeeSjeanPerier                 compDynamicType{addendum->derivedType()}) {
320efd5cdeeSjeanPerier               if (!compDynamicType->noFinalizationNeeded()) {
321efd5cdeeSjeanPerier                 Finalize(compDesc, *compDynamicType, terminator);
322efd5cdeeSjeanPerier               }
323efd5cdeeSjeanPerier             }
324efd5cdeeSjeanPerier           }
325efd5cdeeSjeanPerier         }
326efd5cdeeSjeanPerier       }
327efd5cdeeSjeanPerier     } else if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
32879caf69cSpeter klausler         comp.genre() == typeInfo::Component::Genre::Automatic) {
329a48e4168Speter klausler       if (const typeInfo::DerivedType * compType{comp.derivedType()}) {
33065f52904Speter klausler         if (!compType->noFinalizationNeeded()) {
331e3d6a3acSjeanPerier           for (std::size_t j{0}; j++ < elements;
332e3d6a3acSjeanPerier                descriptor.IncrementSubscripts(at)) {
333e3d6a3acSjeanPerier             const Descriptor &compDesc{
334e3d6a3acSjeanPerier                 *descriptor.ElementComponent<Descriptor>(at, comp.offset())};
33565f52904Speter klausler             if (compDesc.IsAllocated()) {
336b21c24c3SPeter Klausler               Finalize(compDesc, *compType, terminator);
337a48e4168Speter klausler             }
338a48e4168Speter klausler           }
339a48e4168Speter klausler         }
3404fede8bcSpeter klausler       }
34179caf69cSpeter klausler     } else if (comp.genre() == typeInfo::Component::Genre::Data &&
34265f52904Speter klausler         comp.derivedType() && !comp.derivedType()->noFinalizationNeeded()) {
3435f6e0f35SjeanPerier       SubscriptValue extents[maxRank];
3445f6e0f35SjeanPerier       GetComponentExtents(extents, comp, descriptor);
3454fede8bcSpeter klausler       StaticDescriptor<maxRank, true, 0> staticDescriptor;
3464fede8bcSpeter klausler       Descriptor &compDesc{staticDescriptor.descriptor()};
34779caf69cSpeter klausler       const typeInfo::DerivedType &compType{*comp.derivedType()};
348e3d6a3acSjeanPerier       for (std::size_t j{0}; j++ < elements;
349e3d6a3acSjeanPerier            descriptor.IncrementSubscripts(at)) {
3504fede8bcSpeter klausler         compDesc.Establish(compType,
351e3d6a3acSjeanPerier             descriptor.ElementComponent<char>(at, comp.offset()), comp.rank(),
3525f6e0f35SjeanPerier             extents);
353b21c24c3SPeter Klausler         Finalize(compDesc, compType, terminator);
3544fede8bcSpeter klausler       }
3554fede8bcSpeter klausler     }
3564fede8bcSpeter klausler   }
357a48e4168Speter klausler   if (recurse) {
358e3d6a3acSjeanPerier     StaticDescriptor<maxRank, true, 8 /*?*/> statDesc;
359e3d6a3acSjeanPerier     Descriptor &tmpDesc{statDesc.descriptor()};
360e3d6a3acSjeanPerier     tmpDesc = descriptor;
361e3d6a3acSjeanPerier     tmpDesc.raw().attribute = CFI_attribute_pointer;
362e3d6a3acSjeanPerier     tmpDesc.Addendum()->set_derivedType(parentType);
363e3d6a3acSjeanPerier     tmpDesc.raw().elem_len = parentType->sizeInBytes();
364e3d6a3acSjeanPerier     Finalize(tmpDesc, *parentType, terminator);
3654fede8bcSpeter klausler   }
3664fede8bcSpeter klausler }
367a48e4168Speter klausler 
36865f52904Speter klausler // The order of finalization follows Fortran 2018 7.5.6.2, with
369ef44cad5Speter klausler // elementwise finalization of non-parent components taking place
370ef44cad5Speter klausler // before parent component finalization, and with all finalization
371ef44cad5Speter klausler // preceding any deallocation.
3728b953fddSSlava Zakharin RT_API_ATTRS void Destroy(const Descriptor &descriptor, bool finalize,
373b21c24c3SPeter Klausler     const typeInfo::DerivedType &derived, Terminator *terminator) {
37465f52904Speter klausler   if (derived.noDestructionNeeded() || !descriptor.IsAllocated()) {
37565f52904Speter klausler     return;
37665f52904Speter klausler   }
37765f52904Speter klausler   if (finalize && !derived.noFinalizationNeeded()) {
378b21c24c3SPeter Klausler     Finalize(descriptor, derived, terminator);
37965f52904Speter klausler   }
3805f6e0f35SjeanPerier   // Deallocate all direct and indirect allocatable and automatic components.
3815f6e0f35SjeanPerier   // Contrary to finalization, the order of deallocation does not matter.
38265f52904Speter klausler   const Descriptor &componentDesc{derived.component()};
38365f52904Speter klausler   std::size_t myComponents{componentDesc.Elements()};
38465f52904Speter klausler   std::size_t elements{descriptor.Elements()};
385e89a00dbSValentin Clement   SubscriptValue at[maxRank];
386e89a00dbSValentin Clement   descriptor.GetLowerBounds(at);
38765f52904Speter klausler   for (std::size_t k{0}; k < myComponents; ++k) {
38865f52904Speter klausler     const auto &comp{
38965f52904Speter klausler         *componentDesc.ZeroBasedIndexedElement<typeInfo::Component>(k)};
3905f6e0f35SjeanPerier     const bool destroyComp{
3915f6e0f35SjeanPerier         comp.derivedType() && !comp.derivedType()->noDestructionNeeded()};
39265f52904Speter klausler     if (comp.genre() == typeInfo::Component::Genre::Allocatable ||
39365f52904Speter klausler         comp.genre() == typeInfo::Component::Genre::Automatic) {
39465f52904Speter klausler       for (std::size_t j{0}; j < elements; ++j) {
395e3d6a3acSjeanPerier         Descriptor *d{
396e3d6a3acSjeanPerier             descriptor.ElementComponent<Descriptor>(at, comp.offset())};
3975f6e0f35SjeanPerier         if (destroyComp) {
3985f6e0f35SjeanPerier           Destroy(*d, /*finalize=*/false, *comp.derivedType(), terminator);
3995f6e0f35SjeanPerier         }
400e89a00dbSValentin Clement         d->Deallocate();
401e89a00dbSValentin Clement         descriptor.IncrementSubscripts(at);
40265f52904Speter klausler       }
4035f6e0f35SjeanPerier     } else if (destroyComp &&
4045f6e0f35SjeanPerier         comp.genre() == typeInfo::Component::Genre::Data) {
4055f6e0f35SjeanPerier       SubscriptValue extents[maxRank];
4065f6e0f35SjeanPerier       GetComponentExtents(extents, comp, descriptor);
4075f6e0f35SjeanPerier       StaticDescriptor<maxRank, true, 0> staticDescriptor;
4085f6e0f35SjeanPerier       Descriptor &compDesc{staticDescriptor.descriptor()};
4095f6e0f35SjeanPerier       const typeInfo::DerivedType &compType{*comp.derivedType()};
4105f6e0f35SjeanPerier       for (std::size_t j{0}; j++ < elements;
4115f6e0f35SjeanPerier            descriptor.IncrementSubscripts(at)) {
4125f6e0f35SjeanPerier         compDesc.Establish(compType,
4135f6e0f35SjeanPerier             descriptor.ElementComponent<char>(at, comp.offset()), comp.rank(),
4145f6e0f35SjeanPerier             extents);
4155f6e0f35SjeanPerier         Destroy(compDesc, /*finalize=*/false, *comp.derivedType(), terminator);
4165f6e0f35SjeanPerier       }
41765f52904Speter klausler     }
41865f52904Speter klausler   }
41965f52904Speter klausler }
420a48e4168Speter klausler 
4218b953fddSSlava Zakharin RT_API_ATTRS bool HasDynamicComponent(const Descriptor &descriptor) {
422c78b528fSSlava Zakharin   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
423c78b528fSSlava Zakharin     if (const auto *derived = addendum->derivedType()) {
4240d0bd3efSjeanPerier       // Destruction is needed if and only if there are direct or indirect
4250d0bd3efSjeanPerier       // allocatable or automatic components.
4260d0bd3efSjeanPerier       return !derived->noDestructionNeeded();
427c78b528fSSlava Zakharin     }
428c78b528fSSlava Zakharin   }
429c78b528fSSlava Zakharin   return false;
430c78b528fSSlava Zakharin }
431c78b528fSSlava Zakharin 
4328b953fddSSlava Zakharin RT_OFFLOAD_API_GROUP_END
4334fede8bcSpeter klausler } // namespace Fortran::runtime
434