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