//===-- runtime/derived-api.cpp //-----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "flang/Runtime/derived-api.h" #include "derived.h" #include "terminator.h" #include "type-info.h" #include "flang/Runtime/descriptor.h" namespace Fortran::runtime { extern "C" { void RTNAME(Initialize)( const Descriptor &descriptor, const char *sourceFile, int sourceLine) { if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { if (const auto *derived{addendum->derivedType()}) { if (!derived->noInitializationNeeded()) { Terminator terminator{sourceFile, sourceLine}; Initialize(descriptor, *derived, terminator); } } } } void RTNAME(Destroy)(const Descriptor &descriptor) { if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { if (const auto *derived{addendum->derivedType()}) { if (!derived->noDestructionNeeded()) { Destroy(descriptor, true, *derived); } } } } bool RTNAME(ClassIs)( const Descriptor &descriptor, const typeInfo::DerivedType &derivedType) { if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { if (const auto *derived{addendum->derivedType()}) { if (derived == &derivedType) { return true; } const typeInfo::DerivedType *parent{derived->GetParentType()}; while (parent) { if (parent == &derivedType) { return true; } parent = parent->GetParentType(); } } } return false; } static bool CompareDerivedTypeNames(const Descriptor &a, const Descriptor &b) { if (a.raw().version == CFI_VERSION && a.type() == TypeCode{TypeCategory::Character, 1} && a.ElementBytes() > 0 && a.rank() == 0 && a.OffsetElement() != nullptr && a.raw().version == CFI_VERSION && b.type() == TypeCode{TypeCategory::Character, 1} && b.ElementBytes() > 0 && b.rank() == 0 && b.OffsetElement() != nullptr && a.ElementBytes() == b.ElementBytes() && memcmp(a.OffsetElement(), b.OffsetElement(), a.ElementBytes()) == 0) { return true; } return false; } inline bool CompareDerivedType( const typeInfo::DerivedType *a, const typeInfo::DerivedType *b) { return a == b || CompareDerivedTypeNames(a->name(), b->name()); } static const typeInfo::DerivedType *GetDerivedType(const Descriptor &desc) { if (const DescriptorAddendum * addendum{desc.Addendum()}) { if (const auto *derived{addendum->derivedType()}) { return derived; } } return nullptr; } bool RTNAME(SameTypeAs)(const Descriptor &a, const Descriptor &b) { // Unlimited polymorphic with intrinsic dynamic type. if (a.raw().type != CFI_type_struct && a.raw().type != CFI_type_other && b.raw().type != CFI_type_struct && b.raw().type != CFI_type_other) return a.raw().type == b.raw().type; const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)}; const typeInfo::DerivedType *derivedTypeB{GetDerivedType(b)}; // No dynamic type in one or both descriptor. if (derivedTypeA == nullptr || derivedTypeB == nullptr) { return false; } // Exact match of derived type. if (derivedTypeA == derivedTypeB) { return true; } // Otherwise compare with the name. Note 16.29 kind type parameters are not // considered in the test. return CompareDerivedTypeNames(derivedTypeA->name(), derivedTypeB->name()); } bool RTNAME(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) { if (a.raw().type != CFI_type_struct && a.raw().type != CFI_type_other && mold.raw().type != CFI_type_struct && mold.raw().type != CFI_type_other) return a.raw().type == mold.raw().type; const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)}; const typeInfo::DerivedType *derivedTypeMold{GetDerivedType(mold)}; // If MOLD is unlimited polymorphic and is either a disassociated pointer or // unallocated allocatable, the result is true. // Unlimited polymorphic descriptors are initialized with a CFI_type_other // type. if (mold.type().raw() == CFI_type_other && (mold.IsAllocatable() || mold.IsPointer()) && derivedTypeMold == nullptr) { return true; } // If A is unlimited polymorphic and is either a disassociated pointer or // unallocated allocatable, the result is false. // Unlimited polymorphic descriptors are initialized with a CFI_type_other // type. if (a.type().raw() == CFI_type_other && (a.IsAllocatable() || a.IsPointer()) && derivedTypeA == nullptr) { return false; } if (derivedTypeA == nullptr || derivedTypeMold == nullptr) { return false; } // Otherwise if the dynamic type of A or MOLD is extensible, the result is // true if and only if the dynamic type of A is an extension type of the // dynamic type of MOLD. if (CompareDerivedType(derivedTypeA, derivedTypeMold)) { return true; } const typeInfo::DerivedType *parent{derivedTypeA->GetParentType()}; while (parent) { if (CompareDerivedType(parent, derivedTypeMold)) { return true; } parent = parent->GetParentType(); } return false; } } // extern "C" } // namespace Fortran::runtime