xref: /llvm-project/flang/runtime/allocatable.cpp (revision 668f261bfa53d6f9cd9131ca6b1079ec940ab81b)
1 //===-- runtime/allocatable.cpp -------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Runtime/allocatable.h"
10 #include "assign-impl.h"
11 #include "derived.h"
12 #include "stat.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"
18 
19 namespace Fortran::runtime {
20 extern "C" {
21 
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);
28 }
29 
30 void RTNAME(AllocatableInitCharacter)(Descriptor &descriptor,
31     SubscriptValue length, int kind, int rank, int corank) {
32   INTERNAL_CHECK(corank == 0);
33   descriptor.Establish(
34       kind, length, nullptr, rank, nullptr, CFI_attribute_allocatable);
35 }
36 
37 void RTNAME(AllocatableInitDerived)(Descriptor &descriptor,
38     const typeInfo::DerivedType &derivedType, int rank, int corank) {
39   INTERNAL_CHECK(corank == 0);
40   descriptor.Establish(
41       derivedType, nullptr, rank, nullptr, CFI_attribute_allocatable);
42 }
43 
44 void RTNAME(AllocatableInitIntrinsicForAllocate)(Descriptor &descriptor,
45     TypeCategory category, int kind, int rank, int corank) {
46   if (descriptor.IsAllocated()) {
47     return;
48   }
49   RTNAME(AllocatableInitIntrinsic)(descriptor, category, kind, rank, corank);
50 }
51 
52 void RTNAME(AllocatableInitCharacterForAllocate)(Descriptor &descriptor,
53     SubscriptValue length, int kind, int rank, int corank) {
54   if (descriptor.IsAllocated()) {
55     return;
56   }
57   RTNAME(AllocatableInitCharacter)(descriptor, length, kind, rank, corank);
58 }
59 
60 void RTNAME(AllocatableInitDerivedForAllocate)(Descriptor &descriptor,
61     const typeInfo::DerivedType &derivedType, int rank, int corank) {
62   if (descriptor.IsAllocated()) {
63     return;
64   }
65   RTNAME(AllocatableInitDerived)(descriptor, derivedType, rank, corank);
66 }
67 
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};
72 
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()) {
76     return ReturnError(
77         terminator, StatMoveAllocSameAllocatable, errMsg, hasStat);
78   }
79 
80   if (to.IsAllocated()) {
81     int stat{
82         to.Destroy(/*finalize=*/true, /*destroyPointers=*/false, &terminator)};
83     if (stat != StatOk) {
84       return ReturnError(terminator, stat, errMsg, hasStat);
85     }
86   }
87 
88   // If from isn't allocated, the standard defines that nothing should be done.
89   if (from.IsAllocated()) {
90     to = from;
91     from.raw().base_addr = nullptr;
92 
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);
98         }
99       }
100     }
101 
102     // Reset from dynamic type if needed.
103     if (auto *fromAddendum{from.Addendum()}) {
104       if (derivedType) {
105         fromAddendum->set_derivedType(derivedType);
106       }
107     }
108   }
109 
110   return StatOk;
111 }
112 
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.
118 }
119 
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);
125 }
126 
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.
131     return;
132   }
133   descriptor = mold;
134   descriptor.set_base_addr(nullptr);
135   descriptor.raw().attribute = CFI_attribute_allocatable;
136   descriptor.raw().rank = rank;
137   if (auto *descAddendum{descriptor.Addendum()}) {
138     if (const auto *moldAddendum{mold.Addendum()}) {
139       if (const auto *derived{moldAddendum->derivedType()}) {
140         descAddendum->set_derivedType(derived);
141       }
142     }
143   }
144 }
145 
146 int RTNAME(AllocatableAllocate)(Descriptor &descriptor, bool hasStat,
147     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
148   Terminator terminator{sourceFile, sourceLine};
149   if (!descriptor.IsAllocatable()) {
150     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
151   }
152   if (descriptor.IsAllocated()) {
153     return ReturnError(terminator, StatBaseNotNull, errMsg, hasStat);
154   }
155   int stat{ReturnError(terminator, descriptor.Allocate(), errMsg, hasStat)};
156   if (stat == StatOk) {
157     if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
158       if (const auto *derived{addendum->derivedType()}) {
159         if (!derived->noInitializationNeeded()) {
160           stat = Initialize(descriptor, *derived, terminator, hasStat, errMsg);
161         }
162       }
163     }
164   }
165   return stat;
166 }
167 
168 int RTNAME(AllocatableAllocateSource)(Descriptor &alloc,
169     const Descriptor &source, bool hasStat, const Descriptor *errMsg,
170     const char *sourceFile, int sourceLine) {
171   if (alloc.Elements() == 0) {
172     return StatOk;
173   }
174   int stat{RTNAME(AllocatableAllocate)(
175       alloc, hasStat, errMsg, sourceFile, sourceLine)};
176   if (stat == StatOk) {
177     Terminator terminator{sourceFile, sourceLine};
178     DoFromSourceAssign(alloc, source, terminator);
179   }
180   return stat;
181 }
182 
183 int RTNAME(AllocatableDeallocate)(Descriptor &descriptor, bool hasStat,
184     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
185   Terminator terminator{sourceFile, sourceLine};
186   if (!descriptor.IsAllocatable()) {
187     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
188   }
189   if (!descriptor.IsAllocated()) {
190     return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
191   }
192   return ReturnError(terminator,
193       descriptor.Destroy(
194           /*finalize=*/true, /*destroyPointers=*/false, &terminator),
195       errMsg, hasStat);
196 }
197 
198 int RTNAME(AllocatableDeallocatePolymorphic)(Descriptor &descriptor,
199     const typeInfo::DerivedType *derivedType, bool hasStat,
200     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
201   int stat{RTNAME(AllocatableDeallocate)(
202       descriptor, hasStat, errMsg, sourceFile, sourceLine)};
203   if (stat == StatOk) {
204     DescriptorAddendum *addendum{descriptor.Addendum()};
205     if (addendum) {
206       addendum->set_derivedType(derivedType);
207     } else {
208       // Unlimited polymorphic descriptors initialized with
209       // AllocatableInitIntrinsic do not have an addendum. Make sure the
210       // derivedType is null in that case.
211       INTERNAL_CHECK(!derivedType);
212     }
213   }
214   return stat;
215 }
216 
217 void RTNAME(AllocatableDeallocateNoFinal)(
218     Descriptor &descriptor, const char *sourceFile, int sourceLine) {
219   Terminator terminator{sourceFile, sourceLine};
220   if (!descriptor.IsAllocatable()) {
221     ReturnError(terminator, StatInvalidDescriptor);
222   } else if (!descriptor.IsAllocated()) {
223     ReturnError(terminator, StatBaseNull);
224   } else {
225     ReturnError(terminator,
226         descriptor.Destroy(
227             /*finalize=*/false, /*destroyPointers=*/false, &terminator));
228   }
229 }
230 
231 // TODO: AllocatableCheckLengthParameter
232 }
233 } // namespace Fortran::runtime
234