1c1db35f0Speter klausler //===-- runtime/allocatable.cpp -------------------------------------------===//
24d54bb7aSpeter klausler //
34d54bb7aSpeter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d54bb7aSpeter klausler // See https://llvm.org/LICENSE.txt for license information.
54d54bb7aSpeter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d54bb7aSpeter klausler //
74d54bb7aSpeter klausler //===----------------------------------------------------------------------===//
84d54bb7aSpeter klausler
9830c0b90SPeter Klausler #include "flang/Runtime/allocatable.h"
10755535b5SPeter Klausler #include "assign-impl.h"
11a48e4168Speter klausler #include "derived.h"
128df28f0aSpeter klausler #include "stat.h"
134d54bb7aSpeter klausler #include "terminator.h"
14a48e4168Speter klausler #include "type-info.h"
15668f261bSSlava Zakharin #include "flang/ISO_Fortran_binding_wrapper.h"
16e4d9a5e6SDavid Truby #include "flang/Runtime/assign.h"
17e4d9a5e6SDavid Truby #include "flang/Runtime/descriptor.h"
184d54bb7aSpeter klausler
194d54bb7aSpeter klausler namespace Fortran::runtime {
204d54bb7aSpeter klausler extern "C" {
2176facde3SSlava Zakharin RT_EXT_API_GROUP_BEGIN
224d54bb7aSpeter klausler
RTDEF(AllocatableInitIntrinsic)23b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitIntrinsic)(Descriptor &descriptor,
248df28f0aSpeter klausler TypeCategory category, int kind, int rank, int corank) {
258df28f0aSpeter klausler INTERNAL_CHECK(corank == 0);
268df28f0aSpeter klausler descriptor.Establish(TypeCode{category, kind},
278df28f0aSpeter klausler Descriptor::BytesFor(category, kind), nullptr, rank, nullptr,
288df28f0aSpeter klausler CFI_attribute_allocatable);
294d54bb7aSpeter klausler }
304d54bb7aSpeter klausler
RTDEF(AllocatableInitCharacter)31b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitCharacter)(Descriptor &descriptor,
328df28f0aSpeter klausler SubscriptValue length, int kind, int rank, int corank) {
338df28f0aSpeter klausler INTERNAL_CHECK(corank == 0);
348df28f0aSpeter klausler descriptor.Establish(
358df28f0aSpeter klausler kind, length, nullptr, rank, nullptr, CFI_attribute_allocatable);
364d54bb7aSpeter klausler }
374d54bb7aSpeter klausler
RTDEF(AllocatableInitDerived)38b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitDerived)(Descriptor &descriptor,
394fede8bcSpeter klausler const typeInfo::DerivedType &derivedType, int rank, int corank) {
408df28f0aSpeter klausler INTERNAL_CHECK(corank == 0);
418df28f0aSpeter klausler descriptor.Establish(
428df28f0aSpeter klausler derivedType, nullptr, rank, nullptr, CFI_attribute_allocatable);
434d54bb7aSpeter klausler }
444d54bb7aSpeter klausler
RTDEF(AllocatableInitIntrinsicForAllocate)45b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitIntrinsicForAllocate)(Descriptor &descriptor,
4652e23979SValentin Clement TypeCategory category, int kind, int rank, int corank) {
47*9fdd25e1SPeter Klausler if (!descriptor.IsAllocated()) {
4852e23979SValentin Clement RTNAME(AllocatableInitIntrinsic)(descriptor, category, kind, rank, corank);
4952e23979SValentin Clement }
50*9fdd25e1SPeter Klausler }
5152e23979SValentin Clement
RTDEF(AllocatableInitCharacterForAllocate)52b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitCharacterForAllocate)(Descriptor &descriptor,
5352e23979SValentin Clement SubscriptValue length, int kind, int rank, int corank) {
54*9fdd25e1SPeter Klausler if (!descriptor.IsAllocated()) {
5552e23979SValentin Clement RTNAME(AllocatableInitCharacter)(descriptor, length, kind, rank, corank);
5652e23979SValentin Clement }
57*9fdd25e1SPeter Klausler }
5852e23979SValentin Clement
RTDEF(AllocatableInitDerivedForAllocate)59b4b23ff7SSlava Zakharin void RTDEF(AllocatableInitDerivedForAllocate)(Descriptor &descriptor,
6052e23979SValentin Clement const typeInfo::DerivedType &derivedType, int rank, int corank) {
61*9fdd25e1SPeter Klausler if (!descriptor.IsAllocated()) {
6252e23979SValentin Clement RTNAME(AllocatableInitDerived)(descriptor, derivedType, rank, corank);
6352e23979SValentin Clement }
64*9fdd25e1SPeter Klausler }
6552e23979SValentin Clement
RTDEF(MoveAlloc)66b4b23ff7SSlava Zakharin std::int32_t RTDEF(MoveAlloc)(Descriptor &to, Descriptor &from,
67f88bc7d4SValentin Clement const typeInfo::DerivedType *derivedType, bool hasStat,
68e4d9a5e6SDavid Truby const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
69e4d9a5e6SDavid Truby Terminator terminator{sourceFile, sourceLine};
70e4d9a5e6SDavid Truby
71e4d9a5e6SDavid Truby // If to and from are the same allocatable they must not be allocated
72e4d9a5e6SDavid Truby // and nothing should be done.
73e4d9a5e6SDavid Truby if (from.raw().base_addr == to.raw().base_addr && from.IsAllocated()) {
742526013aSDavid Truby return ReturnError(
752526013aSDavid Truby terminator, StatMoveAllocSameAllocatable, errMsg, hasStat);
76e4d9a5e6SDavid Truby }
77e4d9a5e6SDavid Truby
78e4d9a5e6SDavid Truby if (to.IsAllocated()) {
79b21c24c3SPeter Klausler int stat{
80b21c24c3SPeter Klausler to.Destroy(/*finalize=*/true, /*destroyPointers=*/false, &terminator)};
81e4d9a5e6SDavid Truby if (stat != StatOk) {
82e4d9a5e6SDavid Truby return ReturnError(terminator, stat, errMsg, hasStat);
83e4d9a5e6SDavid Truby }
84e4d9a5e6SDavid Truby }
85e4d9a5e6SDavid Truby
86e4d9a5e6SDavid Truby // If from isn't allocated, the standard defines that nothing should be done.
87e4d9a5e6SDavid Truby if (from.IsAllocated()) {
88e4d9a5e6SDavid Truby to = from;
89e4d9a5e6SDavid Truby from.raw().base_addr = nullptr;
90f88bc7d4SValentin Clement
91f88bc7d4SValentin Clement // Carry over the dynamic type.
92f88bc7d4SValentin Clement if (auto *toAddendum{to.Addendum()}) {
93f88bc7d4SValentin Clement if (const auto *fromAddendum{from.Addendum()}) {
94f88bc7d4SValentin Clement if (const auto *derived{fromAddendum->derivedType()}) {
95f88bc7d4SValentin Clement toAddendum->set_derivedType(derived);
96e4d9a5e6SDavid Truby }
97f88bc7d4SValentin Clement }
98f88bc7d4SValentin Clement }
99f88bc7d4SValentin Clement
100f88bc7d4SValentin Clement // Reset from dynamic type if needed.
101f88bc7d4SValentin Clement if (auto *fromAddendum{from.Addendum()}) {
102f88bc7d4SValentin Clement if (derivedType) {
103f88bc7d4SValentin Clement fromAddendum->set_derivedType(derivedType);
104f88bc7d4SValentin Clement }
105f88bc7d4SValentin Clement }
106f88bc7d4SValentin Clement }
107f88bc7d4SValentin Clement
1088df28f0aSpeter klausler return StatOk;
1094d54bb7aSpeter klausler }
1104d54bb7aSpeter klausler
RTDEF(AllocatableSetBounds)111b4b23ff7SSlava Zakharin void RTDEF(AllocatableSetBounds)(Descriptor &descriptor, int zeroBasedDim,
1128df28f0aSpeter klausler SubscriptValue lower, SubscriptValue upper) {
1138df28f0aSpeter klausler INTERNAL_CHECK(zeroBasedDim >= 0 && zeroBasedDim < descriptor.rank());
114*9fdd25e1SPeter Klausler if (descriptor.IsAllocatable() && !descriptor.IsAllocated()) {
1158df28f0aSpeter klausler descriptor.GetDimension(zeroBasedDim).SetBounds(lower, upper);
1168df28f0aSpeter klausler // The byte strides are computed when the object is allocated.
1178df28f0aSpeter klausler }
118*9fdd25e1SPeter Klausler }
1198df28f0aSpeter klausler
RTDEF(AllocatableSetDerivedLength)120b4b23ff7SSlava Zakharin void RTDEF(AllocatableSetDerivedLength)(
121ad424cf1Speter klausler Descriptor &descriptor, int which, SubscriptValue x) {
122*9fdd25e1SPeter Klausler if (descriptor.IsAllocatable() && !descriptor.IsAllocated()) {
123ad424cf1Speter klausler DescriptorAddendum *addendum{descriptor.Addendum()};
124ad424cf1Speter klausler INTERNAL_CHECK(addendum != nullptr);
125ad424cf1Speter klausler addendum->SetLenParameterValue(which, x);
126ad424cf1Speter klausler }
127*9fdd25e1SPeter Klausler }
128ad424cf1Speter klausler
RTDEF(AllocatableApplyMold)129b4b23ff7SSlava Zakharin void RTDEF(AllocatableApplyMold)(
130696ad139SValentin Clement Descriptor &descriptor, const Descriptor &mold, int rank) {
131*9fdd25e1SPeter Klausler if (descriptor.IsAllocatable() && !descriptor.IsAllocated()) {
132dffd93b3SPeter Klausler descriptor.ApplyMold(mold, rank);
133ad424cf1Speter klausler }
134*9fdd25e1SPeter Klausler }
135ad424cf1Speter klausler
RTDEF(AllocatableAllocate)136b4b23ff7SSlava Zakharin int RTDEF(AllocatableAllocate)(Descriptor &descriptor, bool hasStat,
137170e9061Speter klausler const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
1388df28f0aSpeter klausler Terminator terminator{sourceFile, sourceLine};
1398df28f0aSpeter klausler if (!descriptor.IsAllocatable()) {
1408df28f0aSpeter klausler return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
141*9fdd25e1SPeter Klausler } else if (descriptor.IsAllocated()) {
1428df28f0aSpeter klausler return ReturnError(terminator, StatBaseNotNull, errMsg, hasStat);
143*9fdd25e1SPeter Klausler } else {
144a48e4168Speter klausler int stat{ReturnError(terminator, descriptor.Allocate(), errMsg, hasStat)};
145a48e4168Speter klausler if (stat == StatOk) {
146a48e4168Speter klausler if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
147a48e4168Speter klausler if (const auto *derived{addendum->derivedType()}) {
148a48e4168Speter klausler if (!derived->noInitializationNeeded()) {
149*9fdd25e1SPeter Klausler stat =
150*9fdd25e1SPeter Klausler Initialize(descriptor, *derived, terminator, hasStat, errMsg);
151a48e4168Speter klausler }
152a48e4168Speter klausler }
153a48e4168Speter klausler }
154a48e4168Speter klausler }
155a48e4168Speter klausler return stat;
1568df28f0aSpeter klausler }
157*9fdd25e1SPeter Klausler }
1588df28f0aSpeter klausler
RTDEF(AllocatableAllocateSource)159b4b23ff7SSlava Zakharin int RTDEF(AllocatableAllocateSource)(Descriptor &alloc,
1608c77c011SPeixin Qiao const Descriptor &source, bool hasStat, const Descriptor *errMsg,
1618c77c011SPeixin Qiao const char *sourceFile, int sourceLine) {
1628c77c011SPeixin Qiao int stat{RTNAME(AllocatableAllocate)(
1638c77c011SPeixin Qiao alloc, hasStat, errMsg, sourceFile, sourceLine)};
1648c77c011SPeixin Qiao if (stat == StatOk) {
1658c77c011SPeixin Qiao Terminator terminator{sourceFile, sourceLine};
166f783c9bbSPeixin Qiao DoFromSourceAssign(alloc, source, terminator);
1678c77c011SPeixin Qiao }
1688c77c011SPeixin Qiao return stat;
1698c77c011SPeixin Qiao }
1708c77c011SPeixin Qiao
RTDEF(AllocatableDeallocate)171b4b23ff7SSlava Zakharin int RTDEF(AllocatableDeallocate)(Descriptor &descriptor, bool hasStat,
172170e9061Speter klausler const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
1738df28f0aSpeter klausler Terminator terminator{sourceFile, sourceLine};
1748df28f0aSpeter klausler if (!descriptor.IsAllocatable()) {
1758df28f0aSpeter klausler return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
176*9fdd25e1SPeter Klausler } else if (!descriptor.IsAllocated()) {
1778df28f0aSpeter klausler return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
178*9fdd25e1SPeter Klausler } else {
179b21c24c3SPeter Klausler return ReturnError(terminator,
180b21c24c3SPeter Klausler descriptor.Destroy(
181b21c24c3SPeter Klausler /*finalize=*/true, /*destroyPointers=*/false, &terminator),
182b21c24c3SPeter Klausler errMsg, hasStat);
183a48e4168Speter klausler }
184*9fdd25e1SPeter Klausler }
185a48e4168Speter klausler
RTDEF(AllocatableDeallocatePolymorphic)186b4b23ff7SSlava Zakharin int RTDEF(AllocatableDeallocatePolymorphic)(Descriptor &descriptor,
18701e8e50cSValentin Clement const typeInfo::DerivedType *derivedType, bool hasStat,
18801e8e50cSValentin Clement const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
18901e8e50cSValentin Clement int stat{RTNAME(AllocatableDeallocate)(
19001e8e50cSValentin Clement descriptor, hasStat, errMsg, sourceFile, sourceLine)};
19101e8e50cSValentin Clement if (stat == StatOk) {
192dffd93b3SPeter Klausler if (DescriptorAddendum * addendum{descriptor.Addendum()}) {
19301e8e50cSValentin Clement addendum->set_derivedType(derivedType);
194dffd93b3SPeter Klausler descriptor.raw().type = derivedType ? CFI_type_struct : CFI_type_other;
1959ae4e1aeSValentin Clement } else {
1969ae4e1aeSValentin Clement // Unlimited polymorphic descriptors initialized with
1979ae4e1aeSValentin Clement // AllocatableInitIntrinsic do not have an addendum. Make sure the
1989ae4e1aeSValentin Clement // derivedType is null in that case.
1999ae4e1aeSValentin Clement INTERNAL_CHECK(!derivedType);
200dffd93b3SPeter Klausler descriptor.raw().type = CFI_type_other;
2019ae4e1aeSValentin Clement }
20201e8e50cSValentin Clement }
20301e8e50cSValentin Clement return stat;
20401e8e50cSValentin Clement }
20501e8e50cSValentin Clement
RTDEF(AllocatableDeallocateNoFinal)206b4b23ff7SSlava Zakharin void RTDEF(AllocatableDeallocateNoFinal)(
207a48e4168Speter klausler Descriptor &descriptor, const char *sourceFile, int sourceLine) {
208a48e4168Speter klausler Terminator terminator{sourceFile, sourceLine};
209a48e4168Speter klausler if (!descriptor.IsAllocatable()) {
210a48e4168Speter klausler ReturnError(terminator, StatInvalidDescriptor);
211a48e4168Speter klausler } else if (!descriptor.IsAllocated()) {
212a48e4168Speter klausler ReturnError(terminator, StatBaseNull);
213a48e4168Speter klausler } else {
214b21c24c3SPeter Klausler ReturnError(terminator,
215b21c24c3SPeter Klausler descriptor.Destroy(
216b21c24c3SPeter Klausler /*finalize=*/false, /*destroyPointers=*/false, &terminator));
217a48e4168Speter klausler }
2184d54bb7aSpeter klausler }
219ad424cf1Speter klausler
2208c77c011SPeixin Qiao // TODO: AllocatableCheckLengthParameter
22176facde3SSlava Zakharin
22276facde3SSlava Zakharin RT_EXT_API_GROUP_END
2234d54bb7aSpeter klausler }
2244d54bb7aSpeter klausler } // namespace Fortran::runtime
225