xref: /llvm-project/flang/runtime/derived-api.cpp (revision 1fcb6a9754a8db057e18f629cb90011b638901e7)
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