1 //===-- runtime/derived-api.cpp 2 //-----------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "flang/Runtime/derived-api.h" 11 #include "derived.h" 12 #include "terminator.h" 13 #include "tools.h" 14 #include "type-info.h" 15 #include "flang/Runtime/descriptor.h" 16 17 namespace Fortran::runtime { 18 19 extern "C" { 20 RT_EXT_API_GROUP_BEGIN 21 22 void RTDEF(Initialize)( 23 const Descriptor &descriptor, const char *sourceFile, int sourceLine) { 24 if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { 25 if (const auto *derived{addendum->derivedType()}) { 26 if (!derived->noInitializationNeeded()) { 27 Terminator terminator{sourceFile, sourceLine}; 28 Initialize(descriptor, *derived, terminator); 29 } 30 } 31 } 32 } 33 34 void RTDEF(InitializeClone)(const Descriptor &clone, const Descriptor &orig, 35 const char *sourceFile, int sourceLine) { 36 if (const DescriptorAddendum * addendum{clone.Addendum()}) { 37 if (const auto *derived{addendum->derivedType()}) { 38 Terminator terminator{sourceFile, sourceLine}; 39 InitializeClone(clone, orig, *derived, terminator); 40 } 41 } 42 } 43 44 void RTDEF(Destroy)(const Descriptor &descriptor) { 45 if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { 46 if (const auto *derived{addendum->derivedType()}) { 47 if (!derived->noDestructionNeeded()) { 48 // TODO: Pass source file & line information to the API 49 // so that a good Terminator can be passed 50 Destroy(descriptor, true, *derived, nullptr); 51 } 52 } 53 } 54 } 55 56 void RTDEF(Finalize)( 57 const Descriptor &descriptor, const char *sourceFile, int sourceLine) { 58 if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { 59 if (const auto *derived{addendum->derivedType()}) { 60 if (!derived->noFinalizationNeeded()) { 61 Terminator terminator{sourceFile, sourceLine}; 62 Finalize(descriptor, *derived, &terminator); 63 } 64 } 65 } 66 } 67 68 bool RTDEF(ClassIs)( 69 const Descriptor &descriptor, const typeInfo::DerivedType &derivedType) { 70 if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { 71 if (const auto *derived{addendum->derivedType()}) { 72 if (derived == &derivedType) { 73 return true; 74 } 75 const typeInfo::DerivedType *parent{derived->GetParentType()}; 76 while (parent) { 77 if (parent == &derivedType) { 78 return true; 79 } 80 parent = parent->GetParentType(); 81 } 82 } 83 } 84 return false; 85 } 86 87 static RT_API_ATTRS bool CompareDerivedTypeNames( 88 const Descriptor &a, const Descriptor &b) { 89 if (a.raw().version == CFI_VERSION && 90 a.type() == TypeCode{TypeCategory::Character, 1} && 91 a.ElementBytes() > 0 && a.rank() == 0 && a.OffsetElement() != nullptr && 92 a.raw().version == CFI_VERSION && 93 b.type() == TypeCode{TypeCategory::Character, 1} && 94 b.ElementBytes() > 0 && b.rank() == 0 && b.OffsetElement() != nullptr && 95 a.ElementBytes() == b.ElementBytes() && 96 Fortran::runtime::memcmp( 97 a.OffsetElement(), b.OffsetElement(), a.ElementBytes()) == 0) { 98 return true; 99 } 100 return false; 101 } 102 103 inline RT_API_ATTRS bool CompareDerivedType( 104 const typeInfo::DerivedType *a, const typeInfo::DerivedType *b) { 105 return a == b || CompareDerivedTypeNames(a->name(), b->name()); 106 } 107 108 static RT_API_ATTRS const typeInfo::DerivedType *GetDerivedType( 109 const Descriptor &desc) { 110 if (const DescriptorAddendum * addendum{desc.Addendum()}) { 111 if (const auto *derived{addendum->derivedType()}) { 112 return derived; 113 } 114 } 115 return nullptr; 116 } 117 118 bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) { 119 auto aType{a.raw().type}; 120 auto bType{b.raw().type}; 121 if ((aType != CFI_type_struct && aType != CFI_type_other) || 122 (bType != CFI_type_struct && bType != CFI_type_other)) { 123 // If either type is intrinsic, they must match. 124 return aType == bType; 125 } else { 126 const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)}; 127 const typeInfo::DerivedType *derivedTypeB{GetDerivedType(b)}; 128 if (derivedTypeA == nullptr || derivedTypeB == nullptr) { 129 // Unallocated/disassociated CLASS(*) never matches. 130 return false; 131 } else if (derivedTypeA == derivedTypeB) { 132 // Exact match of derived type. 133 return true; 134 } else { 135 // Otherwise compare with the name. Note 16.29 kind type parameters are 136 // not considered in the test. 137 return CompareDerivedTypeNames( 138 derivedTypeA->name(), derivedTypeB->name()); 139 } 140 } 141 } 142 143 bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) { 144 auto aType{a.raw().type}; 145 auto moldType{mold.raw().type}; 146 if ((aType != CFI_type_struct && aType != CFI_type_other) || 147 (moldType != CFI_type_struct && moldType != CFI_type_other)) { 148 // If either type is intrinsic, they must match. 149 return aType == moldType; 150 } else if (const typeInfo::DerivedType * 151 derivedTypeMold{GetDerivedType(mold)}) { 152 // If A is unlimited polymorphic and is either a disassociated pointer or 153 // unallocated allocatable, the result is false. 154 // Otherwise if the dynamic type of A or MOLD is extensible, the result is 155 // true if and only if the dynamic type of A is an extension type of the 156 // dynamic type of MOLD. 157 for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)}; 158 derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) { 159 if (CompareDerivedType(derivedTypeA, derivedTypeMold)) { 160 return true; 161 } 162 } 163 return false; 164 } else { 165 // MOLD is unlimited polymorphic and unallocated/disassociated. 166 return true; 167 } 168 } 169 170 void RTDEF(DestroyWithoutFinalization)(const Descriptor &descriptor) { 171 if (const DescriptorAddendum * addendum{descriptor.Addendum()}) { 172 if (const auto *derived{addendum->derivedType()}) { 173 if (!derived->noDestructionNeeded()) { 174 Destroy(descriptor, /*finalize=*/false, *derived, nullptr); 175 } 176 } 177 } 178 } 179 180 RT_EXT_API_GROUP_END 181 } // extern "C" 182 } // namespace Fortran::runtime 183