| //===-- lib/runtime/derived-api.cpp -----------------------------*- C++ -*-===// |
| // |
| // 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 "flang-rt/runtime/derived.h" |
| #include "flang-rt/runtime/descriptor.h" |
| #include "flang-rt/runtime/terminator.h" |
| #include "flang-rt/runtime/tools.h" |
| #include "flang-rt/runtime/type-info.h" |
| |
| namespace Fortran::runtime { |
| |
| extern "C" { |
| RT_EXT_API_GROUP_BEGIN |
| |
| void RTDEF(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 RTDEF(InitializeClone)(const Descriptor &clone, const Descriptor &orig, |
| const char *sourceFile, int sourceLine) { |
| if (const DescriptorAddendum * addendum{clone.Addendum()}) { |
| if (const auto *derived{addendum->derivedType()}) { |
| Terminator terminator{sourceFile, sourceLine}; |
| InitializeClone(clone, orig, *derived, terminator); |
| } |
| } |
| } |
| |
| void RTDEF(Destroy)(const Descriptor &descriptor) { |
| if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { |
| if (const auto *derived{addendum->derivedType()}) { |
| if (!derived->noDestructionNeeded()) { |
| // TODO: Pass source file & line information to the API |
| // so that a good Terminator can be passed |
| Destroy(descriptor, true, *derived, nullptr); |
| } |
| } |
| } |
| } |
| |
| void RTDEF(Finalize)( |
| const Descriptor &descriptor, const char *sourceFile, int sourceLine) { |
| if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { |
| if (const auto *derived{addendum->derivedType()}) { |
| if (!derived->noFinalizationNeeded()) { |
| Terminator terminator{sourceFile, sourceLine}; |
| Finalize(descriptor, *derived, &terminator); |
| } |
| } |
| } |
| } |
| |
| bool RTDEF(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 RT_API_ATTRS const typeInfo::DerivedType *GetDerivedType( |
| const Descriptor &desc) { |
| if (const DescriptorAddendum * addendum{desc.Addendum()}) { |
| if (const auto *derived{addendum->derivedType()}) { |
| return derived; |
| } |
| } |
| return nullptr; |
| } |
| |
| bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) { |
| auto aType{a.raw().type}; |
| auto bType{b.raw().type}; |
| if ((aType != CFI_type_struct && aType != CFI_type_other) || |
| (bType != CFI_type_struct && bType != CFI_type_other)) { |
| // If either type is intrinsic, they must match. |
| return aType == bType; |
| } else if (const typeInfo::DerivedType * derivedTypeA{GetDerivedType(a)}) { |
| if (const typeInfo::DerivedType * derivedTypeB{GetDerivedType(b)}) { |
| if (derivedTypeA == derivedTypeB) { |
| return true; |
| } else if (const typeInfo::DerivedType * |
| uninstDerivedTypeA{derivedTypeA->uninstantiatedType()}) { |
| // There are KIND type parameters, are these the same type if those |
| // are ignored? |
| const typeInfo::DerivedType *uninstDerivedTypeB{ |
| derivedTypeB->uninstantiatedType()}; |
| return uninstDerivedTypeA == uninstDerivedTypeB; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) { |
| auto aType{a.raw().type}; |
| auto moldType{mold.raw().type}; |
| if ((aType != CFI_type_struct && aType != CFI_type_other) || |
| (moldType != CFI_type_struct && moldType != CFI_type_other)) { |
| // If either type is intrinsic, they must match. |
| return aType == moldType; |
| } else if (const typeInfo::DerivedType * |
| derivedTypeMold{GetDerivedType(mold)}) { |
| // If A is unlimited polymorphic and is either a disassociated pointer or |
| // unallocated allocatable, the result is 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. |
| for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)}; |
| derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) { |
| if (derivedTypeA == derivedTypeMold) { |
| return true; |
| } |
| } |
| return false; |
| } else { |
| // MOLD is unlimited polymorphic and unallocated/disassociated. |
| return true; |
| } |
| } |
| |
| void RTDEF(DestroyWithoutFinalization)(const Descriptor &descriptor) { |
| if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { |
| if (const auto *derived{addendum->derivedType()}) { |
| if (!derived->noDestructionNeeded()) { |
| Destroy(descriptor, /*finalize=*/false, *derived, nullptr); |
| } |
| } |
| } |
| } |
| |
| RT_EXT_API_GROUP_END |
| } // extern "C" |
| } // namespace Fortran::runtime |