1 //===-- runtime/derived-api.cpp
2 //-----------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #include "flang/Runtime/derived-api.h"
12 #include "terminator.h"
14 #include "type-info.h"
15 #include "flang/Runtime/descriptor.h"
17 namespace Fortran::runtime
{
20 RT_EXT_API_GROUP_BEGIN
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
);
34 void RTDEF(Destroy
)(const Descriptor
&descriptor
) {
35 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
36 if (const auto *derived
{addendum
->derivedType()}) {
37 if (!derived
->noDestructionNeeded()) {
38 // TODO: Pass source file & line information to the API
39 // so that a good Terminator can be passed
40 Destroy(descriptor
, true, *derived
, nullptr);
47 const Descriptor
&descriptor
, const char *sourceFile
, int sourceLine
) {
48 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
49 if (const auto *derived
{addendum
->derivedType()}) {
50 if (!derived
->noFinalizationNeeded()) {
51 Terminator terminator
{sourceFile
, sourceLine
};
52 Finalize(descriptor
, *derived
, &terminator
);
59 const Descriptor
&descriptor
, const typeInfo::DerivedType
&derivedType
) {
60 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
61 if (const auto *derived
{addendum
->derivedType()}) {
62 if (derived
== &derivedType
) {
65 const typeInfo::DerivedType
*parent
{derived
->GetParentType()};
67 if (parent
== &derivedType
) {
70 parent
= parent
->GetParentType();
77 static RT_API_ATTRS
bool CompareDerivedTypeNames(
78 const Descriptor
&a
, const Descriptor
&b
) {
79 if (a
.raw().version
== CFI_VERSION
&&
80 a
.type() == TypeCode
{TypeCategory::Character
, 1} &&
81 a
.ElementBytes() > 0 && a
.rank() == 0 && a
.OffsetElement() != nullptr &&
82 a
.raw().version
== CFI_VERSION
&&
83 b
.type() == TypeCode
{TypeCategory::Character
, 1} &&
84 b
.ElementBytes() > 0 && b
.rank() == 0 && b
.OffsetElement() != nullptr &&
85 a
.ElementBytes() == b
.ElementBytes() &&
86 Fortran::runtime::memcmp(
87 a
.OffsetElement(), b
.OffsetElement(), a
.ElementBytes()) == 0) {
93 inline RT_API_ATTRS
bool CompareDerivedType(
94 const typeInfo::DerivedType
*a
, const typeInfo::DerivedType
*b
) {
95 return a
== b
|| CompareDerivedTypeNames(a
->name(), b
->name());
98 static RT_API_ATTRS
const typeInfo::DerivedType
*GetDerivedType(
99 const Descriptor
&desc
) {
100 if (const DescriptorAddendum
* addendum
{desc
.Addendum()}) {
101 if (const auto *derived
{addendum
->derivedType()}) {
108 bool RTDEF(SameTypeAs
)(const Descriptor
&a
, const Descriptor
&b
) {
109 auto aType
{a
.raw().type
};
110 auto bType
{b
.raw().type
};
111 if ((aType
!= CFI_type_struct
&& aType
!= CFI_type_other
) ||
112 (bType
!= CFI_type_struct
&& bType
!= CFI_type_other
)) {
113 // If either type is intrinsic, they must match.
114 return aType
== bType
;
116 const typeInfo::DerivedType
*derivedTypeA
{GetDerivedType(a
)};
117 const typeInfo::DerivedType
*derivedTypeB
{GetDerivedType(b
)};
118 if (derivedTypeA
== nullptr || derivedTypeB
== nullptr) {
119 // Unallocated/disassociated CLASS(*) never matches.
121 } else if (derivedTypeA
== derivedTypeB
) {
122 // Exact match of derived type.
125 // Otherwise compare with the name. Note 16.29 kind type parameters are
126 // not considered in the test.
127 return CompareDerivedTypeNames(
128 derivedTypeA
->name(), derivedTypeB
->name());
133 bool RTDEF(ExtendsTypeOf
)(const Descriptor
&a
, const Descriptor
&mold
) {
134 auto aType
{a
.raw().type
};
135 auto moldType
{mold
.raw().type
};
136 if ((aType
!= CFI_type_struct
&& aType
!= CFI_type_other
) ||
137 (moldType
!= CFI_type_struct
&& moldType
!= CFI_type_other
)) {
138 // If either type is intrinsic, they must match.
139 return aType
== moldType
;
140 } else if (const typeInfo::DerivedType
*
141 derivedTypeMold
{GetDerivedType(mold
)}) {
142 // If A is unlimited polymorphic and is either a disassociated pointer or
143 // unallocated allocatable, the result is false.
144 // Otherwise if the dynamic type of A or MOLD is extensible, the result is
145 // true if and only if the dynamic type of A is an extension type of the
146 // dynamic type of MOLD.
147 for (const typeInfo::DerivedType
*derivedTypeA
{GetDerivedType(a
)};
148 derivedTypeA
; derivedTypeA
= derivedTypeA
->GetParentType()) {
149 if (CompareDerivedType(derivedTypeA
, derivedTypeMold
)) {
155 // MOLD is unlimited polymorphic and unallocated/disassociated.
160 void RTDEF(DestroyWithoutFinalization
)(const Descriptor
&descriptor
) {
161 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
162 if (const auto *derived
{addendum
->derivedType()}) {
163 if (!derived
->noDestructionNeeded()) {
164 Destroy(descriptor
, /*finalize=*/false, *derived
, nullptr);
172 } // namespace Fortran::runtime