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 ©{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 = © 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 == ©) { 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