1 //===-- runtime/allocatable.cpp -------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "flang/Runtime/allocatable.h"
10 #include "assign-impl.h"
13 #include "terminator.h"
14 #include "type-info.h"
15 #include "flang/ISO_Fortran_binding_wrapper.h"
16 #include "flang/Runtime/assign.h"
17 #include "flang/Runtime/descriptor.h"
19 namespace Fortran::runtime
{
22 void RTNAME(AllocatableInitIntrinsic
)(Descriptor
&descriptor
,
23 TypeCategory category
, int kind
, int rank
, int corank
) {
24 INTERNAL_CHECK(corank
== 0);
25 descriptor
.Establish(TypeCode
{category
, kind
},
26 Descriptor::BytesFor(category
, kind
), nullptr, rank
, nullptr,
27 CFI_attribute_allocatable
);
30 void RTNAME(AllocatableInitCharacter
)(Descriptor
&descriptor
,
31 SubscriptValue length
, int kind
, int rank
, int corank
) {
32 INTERNAL_CHECK(corank
== 0);
34 kind
, length
, nullptr, rank
, nullptr, CFI_attribute_allocatable
);
37 void RTNAME(AllocatableInitDerived
)(Descriptor
&descriptor
,
38 const typeInfo::DerivedType
&derivedType
, int rank
, int corank
) {
39 INTERNAL_CHECK(corank
== 0);
41 derivedType
, nullptr, rank
, nullptr, CFI_attribute_allocatable
);
44 void RTNAME(AllocatableInitIntrinsicForAllocate
)(Descriptor
&descriptor
,
45 TypeCategory category
, int kind
, int rank
, int corank
) {
46 if (descriptor
.IsAllocated()) {
49 RTNAME(AllocatableInitIntrinsic
)(descriptor
, category
, kind
, rank
, corank
);
52 void RTNAME(AllocatableInitCharacterForAllocate
)(Descriptor
&descriptor
,
53 SubscriptValue length
, int kind
, int rank
, int corank
) {
54 if (descriptor
.IsAllocated()) {
57 RTNAME(AllocatableInitCharacter
)(descriptor
, length
, kind
, rank
, corank
);
60 void RTNAME(AllocatableInitDerivedForAllocate
)(Descriptor
&descriptor
,
61 const typeInfo::DerivedType
&derivedType
, int rank
, int corank
) {
62 if (descriptor
.IsAllocated()) {
65 RTNAME(AllocatableInitDerived
)(descriptor
, derivedType
, rank
, corank
);
68 std::int32_t RTNAME(MoveAlloc
)(Descriptor
&to
, Descriptor
&from
,
69 const typeInfo::DerivedType
*derivedType
, bool hasStat
,
70 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
71 Terminator terminator
{sourceFile
, sourceLine
};
73 // If to and from are the same allocatable they must not be allocated
74 // and nothing should be done.
75 if (from
.raw().base_addr
== to
.raw().base_addr
&& from
.IsAllocated()) {
77 terminator
, StatMoveAllocSameAllocatable
, errMsg
, hasStat
);
80 if (to
.IsAllocated()) {
82 to
.Destroy(/*finalize=*/true, /*destroyPointers=*/false, &terminator
)};
84 return ReturnError(terminator
, stat
, errMsg
, hasStat
);
88 // If from isn't allocated, the standard defines that nothing should be done.
89 if (from
.IsAllocated()) {
91 from
.raw().base_addr
= nullptr;
93 // Carry over the dynamic type.
94 if (auto *toAddendum
{to
.Addendum()}) {
95 if (const auto *fromAddendum
{from
.Addendum()}) {
96 if (const auto *derived
{fromAddendum
->derivedType()}) {
97 toAddendum
->set_derivedType(derived
);
102 // Reset from dynamic type if needed.
103 if (auto *fromAddendum
{from
.Addendum()}) {
105 fromAddendum
->set_derivedType(derivedType
);
113 void RTNAME(AllocatableSetBounds
)(Descriptor
&descriptor
, int zeroBasedDim
,
114 SubscriptValue lower
, SubscriptValue upper
) {
115 INTERNAL_CHECK(zeroBasedDim
>= 0 && zeroBasedDim
< descriptor
.rank());
116 descriptor
.GetDimension(zeroBasedDim
).SetBounds(lower
, upper
);
117 // The byte strides are computed when the object is allocated.
120 void RTNAME(AllocatableSetDerivedLength
)(
121 Descriptor
&descriptor
, int which
, SubscriptValue x
) {
122 DescriptorAddendum
*addendum
{descriptor
.Addendum()};
123 INTERNAL_CHECK(addendum
!= nullptr);
124 addendum
->SetLenParameterValue(which
, x
);
127 void RTNAME(AllocatableApplyMold
)(
128 Descriptor
&descriptor
, const Descriptor
&mold
, int rank
) {
129 if (descriptor
.IsAllocated()) {
130 // 9.7.1.3 Return so the error can be emitted by AllocatableAllocate.
133 descriptor
.ApplyMold(mold
, rank
);
136 int RTNAME(AllocatableAllocate
)(Descriptor
&descriptor
, bool hasStat
,
137 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
138 Terminator terminator
{sourceFile
, sourceLine
};
139 if (!descriptor
.IsAllocatable()) {
140 return ReturnError(terminator
, StatInvalidDescriptor
, errMsg
, hasStat
);
142 if (descriptor
.IsAllocated()) {
143 return ReturnError(terminator
, StatBaseNotNull
, errMsg
, hasStat
);
145 int stat
{ReturnError(terminator
, descriptor
.Allocate(), errMsg
, hasStat
)};
146 if (stat
== StatOk
) {
147 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
148 if (const auto *derived
{addendum
->derivedType()}) {
149 if (!derived
->noInitializationNeeded()) {
150 stat
= Initialize(descriptor
, *derived
, terminator
, hasStat
, errMsg
);
158 int RTNAME(AllocatableAllocateSource
)(Descriptor
&alloc
,
159 const Descriptor
&source
, bool hasStat
, const Descriptor
*errMsg
,
160 const char *sourceFile
, int sourceLine
) {
161 int stat
{RTNAME(AllocatableAllocate
)(
162 alloc
, hasStat
, errMsg
, sourceFile
, sourceLine
)};
163 if (stat
== StatOk
) {
164 Terminator terminator
{sourceFile
, sourceLine
};
165 DoFromSourceAssign(alloc
, source
, terminator
);
170 int RTNAME(AllocatableDeallocate
)(Descriptor
&descriptor
, bool hasStat
,
171 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
172 Terminator terminator
{sourceFile
, sourceLine
};
173 if (!descriptor
.IsAllocatable()) {
174 return ReturnError(terminator
, StatInvalidDescriptor
, errMsg
, hasStat
);
176 if (!descriptor
.IsAllocated()) {
177 return ReturnError(terminator
, StatBaseNull
, errMsg
, hasStat
);
179 return ReturnError(terminator
,
181 /*finalize=*/true, /*destroyPointers=*/false, &terminator
),
185 int RTNAME(AllocatableDeallocatePolymorphic
)(Descriptor
&descriptor
,
186 const typeInfo::DerivedType
*derivedType
, bool hasStat
,
187 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
188 int stat
{RTNAME(AllocatableDeallocate
)(
189 descriptor
, hasStat
, errMsg
, sourceFile
, sourceLine
)};
190 if (stat
== StatOk
) {
191 if (DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
192 addendum
->set_derivedType(derivedType
);
193 descriptor
.raw().type
= derivedType
? CFI_type_struct
: CFI_type_other
;
195 // Unlimited polymorphic descriptors initialized with
196 // AllocatableInitIntrinsic do not have an addendum. Make sure the
197 // derivedType is null in that case.
198 INTERNAL_CHECK(!derivedType
);
199 descriptor
.raw().type
= CFI_type_other
;
205 void RTNAME(AllocatableDeallocateNoFinal
)(
206 Descriptor
&descriptor
, const char *sourceFile
, int sourceLine
) {
207 Terminator terminator
{sourceFile
, sourceLine
};
208 if (!descriptor
.IsAllocatable()) {
209 ReturnError(terminator
, StatInvalidDescriptor
);
210 } else if (!descriptor
.IsAllocated()) {
211 ReturnError(terminator
, StatBaseNull
);
213 ReturnError(terminator
,
215 /*finalize=*/false, /*destroyPointers=*/false, &terminator
));
219 // TODO: AllocatableCheckLengthParameter
221 } // namespace Fortran::runtime