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.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 std::int32_t RTNAME(MoveAlloc
)(Descriptor
&to
, Descriptor
&from
, bool hasStat
,
45 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
46 Terminator terminator
{sourceFile
, sourceLine
};
47 // Should be handled by semantic analysis
48 RUNTIME_CHECK(terminator
, to
.type() == from
.type());
49 RUNTIME_CHECK(terminator
, to
.IsAllocatable() && from
.IsAllocatable());
51 // If to and from are the same allocatable they must not be allocated
52 // and nothing should be done.
53 if (from
.raw().base_addr
== to
.raw().base_addr
&& from
.IsAllocated()) {
55 terminator
, StatMoveAllocSameAllocatable
, errMsg
, hasStat
);
58 if (to
.IsAllocated()) {
59 int stat
{to
.Destroy(/*finalize=*/true)};
61 return ReturnError(terminator
, stat
, errMsg
, hasStat
);
65 // If from isn't allocated, the standard defines that nothing should be done.
66 if (from
.IsAllocated()) {
68 from
.raw().base_addr
= nullptr;
73 void RTNAME(AllocatableSetBounds
)(Descriptor
&descriptor
, int zeroBasedDim
,
74 SubscriptValue lower
, SubscriptValue upper
) {
75 INTERNAL_CHECK(zeroBasedDim
>= 0 && zeroBasedDim
< descriptor
.rank());
76 descriptor
.GetDimension(zeroBasedDim
).SetBounds(lower
, upper
);
77 // The byte strides are computed when the object is allocated.
80 void RTNAME(AllocatableSetDerivedLength
)(
81 Descriptor
&descriptor
, int which
, SubscriptValue x
) {
82 DescriptorAddendum
*addendum
{descriptor
.Addendum()};
83 INTERNAL_CHECK(addendum
!= nullptr);
84 addendum
->SetLenParameterValue(which
, x
);
87 void RTNAME(AllocatableApplyMold
)(
88 Descriptor
&descriptor
, const Descriptor
&mold
, int rank
) {
89 if (descriptor
.IsAllocated()) {
90 // 9.7.1.3 Return so the error can be emitted by AllocatableAllocate.
94 descriptor
.set_base_addr(nullptr);
95 descriptor
.raw().attribute
= CFI_attribute_allocatable
;
96 descriptor
.raw().rank
= rank
;
97 if (auto *descAddendum
{descriptor
.Addendum()}) {
98 if (const auto *moldAddendum
{mold
.Addendum()}) {
99 if (const auto *derived
{moldAddendum
->derivedType()}) {
100 descAddendum
->set_derivedType(derived
);
106 int RTNAME(AllocatableAllocate
)(Descriptor
&descriptor
, bool hasStat
,
107 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
108 Terminator terminator
{sourceFile
, sourceLine
};
109 if (!descriptor
.IsAllocatable()) {
110 return ReturnError(terminator
, StatInvalidDescriptor
, errMsg
, hasStat
);
112 if (descriptor
.IsAllocated()) {
113 return ReturnError(terminator
, StatBaseNotNull
, errMsg
, hasStat
);
115 int stat
{ReturnError(terminator
, descriptor
.Allocate(), errMsg
, hasStat
)};
116 if (stat
== StatOk
) {
117 if (const DescriptorAddendum
* addendum
{descriptor
.Addendum()}) {
118 if (const auto *derived
{addendum
->derivedType()}) {
119 if (!derived
->noInitializationNeeded()) {
120 stat
= Initialize(descriptor
, *derived
, terminator
, hasStat
, errMsg
);
128 int RTNAME(AllocatableAllocateSource
)(Descriptor
&alloc
,
129 const Descriptor
&source
, bool hasStat
, const Descriptor
*errMsg
,
130 const char *sourceFile
, int sourceLine
) {
131 if (alloc
.Elements() == 0) {
134 int stat
{RTNAME(AllocatableAllocate
)(
135 alloc
, hasStat
, errMsg
, sourceFile
, sourceLine
)};
136 if (stat
== StatOk
) {
137 Terminator terminator
{sourceFile
, sourceLine
};
138 DoFromSourceAssign(alloc
, source
, terminator
);
143 int RTNAME(AllocatableDeallocate
)(Descriptor
&descriptor
, bool hasStat
,
144 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
145 Terminator terminator
{sourceFile
, sourceLine
};
146 if (!descriptor
.IsAllocatable()) {
147 return ReturnError(terminator
, StatInvalidDescriptor
, errMsg
, hasStat
);
149 if (!descriptor
.IsAllocated()) {
150 return ReturnError(terminator
, StatBaseNull
, errMsg
, hasStat
);
152 return ReturnError(terminator
, descriptor
.Destroy(true), errMsg
, hasStat
);
155 int RTNAME(AllocatableDeallocatePolymorphic
)(Descriptor
&descriptor
,
156 const typeInfo::DerivedType
*derivedType
, bool hasStat
,
157 const Descriptor
*errMsg
, const char *sourceFile
, int sourceLine
) {
158 int stat
{RTNAME(AllocatableDeallocate
)(
159 descriptor
, hasStat
, errMsg
, sourceFile
, sourceLine
)};
160 if (stat
== StatOk
) {
161 DescriptorAddendum
*addendum
{descriptor
.Addendum()};
162 if (addendum
) { // Unlimited polymorphic allocated from intrinsic type spec
164 addendum
->set_derivedType(derivedType
);
166 // Unlimited polymorphic descriptors initialized with
167 // AllocatableInitIntrinsic do not have an addendum. Make sure the
168 // derivedType is null in that case.
169 INTERNAL_CHECK(!derivedType
);
175 void RTNAME(AllocatableDeallocateNoFinal
)(
176 Descriptor
&descriptor
, const char *sourceFile
, int sourceLine
) {
177 Terminator terminator
{sourceFile
, sourceLine
};
178 if (!descriptor
.IsAllocatable()) {
179 ReturnError(terminator
, StatInvalidDescriptor
);
180 } else if (!descriptor
.IsAllocated()) {
181 ReturnError(terminator
, StatBaseNull
);
183 ReturnError(terminator
, descriptor
.Destroy(false));
187 // TODO: AllocatableCheckLengthParameter
189 } // namespace Fortran::runtime