xref: /llvm-project/flang/runtime/derived-api.cpp (revision 1fcb6a9754a8db057e18f629cb90011b638901e7)
1a48e4168Speter klausler //===-- runtime/derived-api.cpp
2a48e4168Speter klausler //-----------------------------------------------===//
3a48e4168Speter klausler //
4a48e4168Speter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5a48e4168Speter klausler // See https://llvm.org/LICENSE.txt for license information.
6a48e4168Speter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7a48e4168Speter klausler //
8a48e4168Speter klausler //===----------------------------------------------------------------------===//
9a48e4168Speter klausler 
10830c0b90SPeter Klausler #include "flang/Runtime/derived-api.h"
11a48e4168Speter klausler #include "derived.h"
12a48e4168Speter klausler #include "terminator.h"
13b4b23ff7SSlava Zakharin #include "tools.h"
14a48e4168Speter klausler #include "type-info.h"
15830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
16a48e4168Speter klausler 
17a48e4168Speter klausler namespace Fortran::runtime {
18a48e4168Speter klausler 
19a48e4168Speter klausler extern "C" {
2076facde3SSlava Zakharin RT_EXT_API_GROUP_BEGIN
21a48e4168Speter klausler 
22b4b23ff7SSlava Zakharin void RTDEF(Initialize)(
23a48e4168Speter klausler     const Descriptor &descriptor, const char *sourceFile, int sourceLine) {
24a48e4168Speter klausler   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
25a48e4168Speter klausler     if (const auto *derived{addendum->derivedType()}) {
26a48e4168Speter klausler       if (!derived->noInitializationNeeded()) {
27a48e4168Speter klausler         Terminator terminator{sourceFile, sourceLine};
28a48e4168Speter klausler         Initialize(descriptor, *derived, terminator);
29a48e4168Speter klausler       }
30a48e4168Speter klausler     }
31a48e4168Speter klausler   }
32a48e4168Speter klausler }
33a48e4168Speter klausler 
34*1fcb6a97SLeandro Lupori void RTDEF(InitializeClone)(const Descriptor &clone, const Descriptor &orig,
35*1fcb6a97SLeandro Lupori     const char *sourceFile, int sourceLine) {
36*1fcb6a97SLeandro Lupori   if (const DescriptorAddendum * addendum{clone.Addendum()}) {
37*1fcb6a97SLeandro Lupori     if (const auto *derived{addendum->derivedType()}) {
38*1fcb6a97SLeandro Lupori       Terminator terminator{sourceFile, sourceLine};
39*1fcb6a97SLeandro Lupori       InitializeClone(clone, orig, *derived, terminator);
40*1fcb6a97SLeandro Lupori     }
41*1fcb6a97SLeandro Lupori   }
42*1fcb6a97SLeandro Lupori }
43*1fcb6a97SLeandro Lupori 
44b4b23ff7SSlava Zakharin void RTDEF(Destroy)(const Descriptor &descriptor) {
45a48e4168Speter klausler   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
46a48e4168Speter klausler     if (const auto *derived{addendum->derivedType()}) {
47a48e4168Speter klausler       if (!derived->noDestructionNeeded()) {
48b21c24c3SPeter Klausler         // TODO: Pass source file & line information to the API
49b21c24c3SPeter Klausler         // so that a good Terminator can be passed
50b21c24c3SPeter Klausler         Destroy(descriptor, true, *derived, nullptr);
51a48e4168Speter klausler       }
52a48e4168Speter klausler     }
53a48e4168Speter klausler   }
54a48e4168Speter klausler }
55a48e4168Speter klausler 
56b4b23ff7SSlava Zakharin void RTDEF(Finalize)(
57ab1db262SSlava Zakharin     const Descriptor &descriptor, const char *sourceFile, int sourceLine) {
58ab1db262SSlava Zakharin   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
59ab1db262SSlava Zakharin     if (const auto *derived{addendum->derivedType()}) {
60ab1db262SSlava Zakharin       if (!derived->noFinalizationNeeded()) {
61ab1db262SSlava Zakharin         Terminator terminator{sourceFile, sourceLine};
62ab1db262SSlava Zakharin         Finalize(descriptor, *derived, &terminator);
63ab1db262SSlava Zakharin       }
64ab1db262SSlava Zakharin     }
65ab1db262SSlava Zakharin   }
66ab1db262SSlava Zakharin }
67ab1db262SSlava Zakharin 
68b4b23ff7SSlava Zakharin bool RTDEF(ClassIs)(
698dfd8835SValentin Clement     const Descriptor &descriptor, const typeInfo::DerivedType &derivedType) {
708dfd8835SValentin Clement   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
718dfd8835SValentin Clement     if (const auto *derived{addendum->derivedType()}) {
728dfd8835SValentin Clement       if (derived == &derivedType) {
738dfd8835SValentin Clement         return true;
748dfd8835SValentin Clement       }
758dfd8835SValentin Clement       const typeInfo::DerivedType *parent{derived->GetParentType()};
768dfd8835SValentin Clement       while (parent) {
778dfd8835SValentin Clement         if (parent == &derivedType) {
788dfd8835SValentin Clement           return true;
798dfd8835SValentin Clement         }
808dfd8835SValentin Clement         parent = parent->GetParentType();
818dfd8835SValentin Clement       }
828dfd8835SValentin Clement     }
838dfd8835SValentin Clement   }
848dfd8835SValentin Clement   return false;
858dfd8835SValentin Clement }
868dfd8835SValentin Clement 
87b4b23ff7SSlava Zakharin static RT_API_ATTRS bool CompareDerivedTypeNames(
88b4b23ff7SSlava Zakharin     const Descriptor &a, const Descriptor &b) {
894bb17511SValentin Clement   if (a.raw().version == CFI_VERSION &&
904bb17511SValentin Clement       a.type() == TypeCode{TypeCategory::Character, 1} &&
914bb17511SValentin Clement       a.ElementBytes() > 0 && a.rank() == 0 && a.OffsetElement() != nullptr &&
924bb17511SValentin Clement       a.raw().version == CFI_VERSION &&
934bb17511SValentin Clement       b.type() == TypeCode{TypeCategory::Character, 1} &&
944bb17511SValentin Clement       b.ElementBytes() > 0 && b.rank() == 0 && b.OffsetElement() != nullptr &&
954bb17511SValentin Clement       a.ElementBytes() == b.ElementBytes() &&
96b4b23ff7SSlava Zakharin       Fortran::runtime::memcmp(
97b4b23ff7SSlava Zakharin           a.OffsetElement(), b.OffsetElement(), a.ElementBytes()) == 0) {
984bb17511SValentin Clement     return true;
994bb17511SValentin Clement   }
1004bb17511SValentin Clement   return false;
1014bb17511SValentin Clement }
1024bb17511SValentin Clement 
103b4b23ff7SSlava Zakharin inline RT_API_ATTRS bool CompareDerivedType(
10487bd9461SValentin Clement     const typeInfo::DerivedType *a, const typeInfo::DerivedType *b) {
10587bd9461SValentin Clement   return a == b || CompareDerivedTypeNames(a->name(), b->name());
10687bd9461SValentin Clement }
10787bd9461SValentin Clement 
1088ebf4084SSlava Zakharin static RT_API_ATTRS const typeInfo::DerivedType *GetDerivedType(
109b4b23ff7SSlava Zakharin     const Descriptor &desc) {
1104bb17511SValentin Clement   if (const DescriptorAddendum * addendum{desc.Addendum()}) {
1114bb17511SValentin Clement     if (const auto *derived{addendum->derivedType()}) {
1124bb17511SValentin Clement       return derived;
1134bb17511SValentin Clement     }
1144bb17511SValentin Clement   }
1154bb17511SValentin Clement   return nullptr;
1164bb17511SValentin Clement }
1174bb17511SValentin Clement 
118b4b23ff7SSlava Zakharin bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) {
119dffd93b3SPeter Klausler   auto aType{a.raw().type};
120dffd93b3SPeter Klausler   auto bType{b.raw().type};
121dffd93b3SPeter Klausler   if ((aType != CFI_type_struct && aType != CFI_type_other) ||
122dffd93b3SPeter Klausler       (bType != CFI_type_struct && bType != CFI_type_other)) {
123dffd93b3SPeter Klausler     // If either type is intrinsic, they must match.
124dffd93b3SPeter Klausler     return aType == bType;
125dffd93b3SPeter Klausler   } else {
1264bb17511SValentin Clement     const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
1274bb17511SValentin Clement     const typeInfo::DerivedType *derivedTypeB{GetDerivedType(b)};
128188c02daSValentin Clement     if (derivedTypeA == nullptr || derivedTypeB == nullptr) {
129dffd93b3SPeter Klausler       // Unallocated/disassociated CLASS(*) never matches.
130188c02daSValentin Clement       return false;
131dffd93b3SPeter Klausler     } else if (derivedTypeA == derivedTypeB) {
1324bb17511SValentin Clement       // Exact match of derived type.
1334bb17511SValentin Clement       return true;
134dffd93b3SPeter Klausler     } else {
135dffd93b3SPeter Klausler       // Otherwise compare with the name. Note 16.29 kind type parameters are
136dffd93b3SPeter Klausler       // not considered in the test.
137dffd93b3SPeter Klausler       return CompareDerivedTypeNames(
138dffd93b3SPeter Klausler           derivedTypeA->name(), derivedTypeB->name());
1394bb17511SValentin Clement     }
140dffd93b3SPeter Klausler   }
1414bb17511SValentin Clement }
1424bb17511SValentin Clement 
143b4b23ff7SSlava Zakharin bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
144dffd93b3SPeter Klausler   auto aType{a.raw().type};
145dffd93b3SPeter Klausler   auto moldType{mold.raw().type};
146dffd93b3SPeter Klausler   if ((aType != CFI_type_struct && aType != CFI_type_other) ||
147dffd93b3SPeter Klausler       (moldType != CFI_type_struct && moldType != CFI_type_other)) {
148dffd93b3SPeter Klausler     // If either type is intrinsic, they must match.
149dffd93b3SPeter Klausler     return aType == moldType;
150dffd93b3SPeter Klausler   } else if (const typeInfo::DerivedType *
151dffd93b3SPeter Klausler       derivedTypeMold{GetDerivedType(mold)}) {
15287bd9461SValentin Clement     // If A is unlimited polymorphic and is either a disassociated pointer or
15387bd9461SValentin Clement     // unallocated allocatable, the result is false.
15487bd9461SValentin Clement     // Otherwise if the dynamic type of A or MOLD is extensible, the result is
15587bd9461SValentin Clement     // true if and only if the dynamic type of A is an extension type of the
15687bd9461SValentin Clement     // dynamic type of MOLD.
157dffd93b3SPeter Klausler     for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
158dffd93b3SPeter Klausler          derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
15987bd9461SValentin Clement       if (CompareDerivedType(derivedTypeA, derivedTypeMold)) {
16087bd9461SValentin Clement         return true;
16187bd9461SValentin Clement       }
16287bd9461SValentin Clement     }
16387bd9461SValentin Clement     return false;
164dffd93b3SPeter Klausler   } else {
165dffd93b3SPeter Klausler     // MOLD is unlimited polymorphic and unallocated/disassociated.
166dffd93b3SPeter Klausler     return true;
167dffd93b3SPeter Klausler   }
16887bd9461SValentin Clement }
16987bd9461SValentin Clement 
170b4b23ff7SSlava Zakharin void RTDEF(DestroyWithoutFinalization)(const Descriptor &descriptor) {
171da60b9e7SSlava Zakharin   if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
172da60b9e7SSlava Zakharin     if (const auto *derived{addendum->derivedType()}) {
173da60b9e7SSlava Zakharin       if (!derived->noDestructionNeeded()) {
174b21c24c3SPeter Klausler         Destroy(descriptor, /*finalize=*/false, *derived, nullptr);
175da60b9e7SSlava Zakharin       }
176da60b9e7SSlava Zakharin     }
177da60b9e7SSlava Zakharin   }
178da60b9e7SSlava Zakharin }
179da60b9e7SSlava Zakharin 
18076facde3SSlava Zakharin RT_EXT_API_GROUP_END
181a48e4168Speter klausler } // extern "C"
182a48e4168Speter klausler } // namespace Fortran::runtime
183