xref: /llvm-project/flang/runtime/allocatable.cpp (revision b4b23ff7f8f258320986ae6af4ded5d87c7ac7e5)
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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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 RTDEF(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.ApplyMold(mold, rank);
134 }
135 
136 int RTDEF(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);
141   }
142   if (descriptor.IsAllocated()) {
143     return ReturnError(terminator, StatBaseNotNull, errMsg, hasStat);
144   }
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);
151         }
152       }
153     }
154   }
155   return stat;
156 }
157 
158 int RTDEF(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);
166   }
167   return stat;
168 }
169 
170 int RTDEF(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);
175   }
176   if (!descriptor.IsAllocated()) {
177     return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
178   }
179   return ReturnError(terminator,
180       descriptor.Destroy(
181           /*finalize=*/true, /*destroyPointers=*/false, &terminator),
182       errMsg, hasStat);
183 }
184 
185 int RTDEF(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;
194     } else {
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;
200     }
201   }
202   return stat;
203 }
204 
205 void RTDEF(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);
212   } else {
213     ReturnError(terminator,
214         descriptor.Destroy(
215             /*finalize=*/false, /*destroyPointers=*/false, &terminator));
216   }
217 }
218 
219 // TODO: AllocatableCheckLengthParameter
220 }
221 } // namespace Fortran::runtime
222