xref: /llvm-project/flang/runtime/allocatable.cpp (revision 8fd3bfc25e49ed82e6287240e9c0ae9f7db76c72)
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.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 std::int32_t RTNAME(MoveAlloc)(Descriptor &to, Descriptor &from,
45     const typeInfo::DerivedType *derivedType, bool hasStat,
46     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
47   Terminator terminator{sourceFile, sourceLine};
48 
49   // If to and from are the same allocatable they must not be allocated
50   // and nothing should be done.
51   if (from.raw().base_addr == to.raw().base_addr && from.IsAllocated()) {
52     return ReturnError(
53         terminator, StatMoveAllocSameAllocatable, errMsg, hasStat);
54   }
55 
56   if (to.IsAllocated()) {
57     int stat{to.Destroy(/*finalize=*/true)};
58     if (stat != StatOk) {
59       return ReturnError(terminator, stat, errMsg, hasStat);
60     }
61   }
62 
63   // If from isn't allocated, the standard defines that nothing should be done.
64   if (from.IsAllocated()) {
65     to = from;
66     from.raw().base_addr = nullptr;
67 
68     // Carry over the dynamic type.
69     if (auto *toAddendum{to.Addendum()}) {
70       if (const auto *fromAddendum{from.Addendum()}) {
71         if (const auto *derived{fromAddendum->derivedType()}) {
72           toAddendum->set_derivedType(derived);
73         }
74       }
75     }
76 
77     // Reset from dynamic type if needed.
78     if (auto *fromAddendum{from.Addendum()}) {
79       if (derivedType) {
80         fromAddendum->set_derivedType(derivedType);
81       }
82     }
83   }
84 
85   return StatOk;
86 }
87 
88 void RTNAME(AllocatableSetBounds)(Descriptor &descriptor, int zeroBasedDim,
89     SubscriptValue lower, SubscriptValue upper) {
90   INTERNAL_CHECK(zeroBasedDim >= 0 && zeroBasedDim < descriptor.rank());
91   descriptor.GetDimension(zeroBasedDim).SetBounds(lower, upper);
92   // The byte strides are computed when the object is allocated.
93 }
94 
95 void RTNAME(AllocatableSetDerivedLength)(
96     Descriptor &descriptor, int which, SubscriptValue x) {
97   DescriptorAddendum *addendum{descriptor.Addendum()};
98   INTERNAL_CHECK(addendum != nullptr);
99   addendum->SetLenParameterValue(which, x);
100 }
101 
102 void RTNAME(AllocatableApplyMold)(
103     Descriptor &descriptor, const Descriptor &mold, int rank) {
104   if (descriptor.IsAllocated()) {
105     // 9.7.1.3 Return so the error can be emitted by AllocatableAllocate.
106     return;
107   }
108   descriptor = mold;
109   descriptor.set_base_addr(nullptr);
110   descriptor.raw().attribute = CFI_attribute_allocatable;
111   descriptor.raw().rank = rank;
112   if (auto *descAddendum{descriptor.Addendum()}) {
113     if (const auto *moldAddendum{mold.Addendum()}) {
114       if (const auto *derived{moldAddendum->derivedType()}) {
115         descAddendum->set_derivedType(derived);
116       }
117     }
118   }
119 }
120 
121 int RTNAME(AllocatableAllocate)(Descriptor &descriptor, bool hasStat,
122     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
123   Terminator terminator{sourceFile, sourceLine};
124   if (!descriptor.IsAllocatable()) {
125     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
126   }
127   if (descriptor.IsAllocated()) {
128     return ReturnError(terminator, StatBaseNotNull, errMsg, hasStat);
129   }
130   int stat{ReturnError(terminator, descriptor.Allocate(), errMsg, hasStat)};
131   if (stat == StatOk) {
132     if (const DescriptorAddendum * addendum{descriptor.Addendum()}) {
133       if (const auto *derived{addendum->derivedType()}) {
134         if (!derived->noInitializationNeeded()) {
135           stat = Initialize(descriptor, *derived, terminator, hasStat, errMsg);
136         }
137       }
138     }
139   }
140   return stat;
141 }
142 
143 int RTNAME(AllocatableAllocateSource)(Descriptor &alloc,
144     const Descriptor &source, bool hasStat, const Descriptor *errMsg,
145     const char *sourceFile, int sourceLine) {
146   if (alloc.Elements() == 0) {
147     return StatOk;
148   }
149   int stat{RTNAME(AllocatableAllocate)(
150       alloc, hasStat, errMsg, sourceFile, sourceLine)};
151   if (stat == StatOk) {
152     Terminator terminator{sourceFile, sourceLine};
153     DoFromSourceAssign(alloc, source, terminator);
154   }
155   return stat;
156 }
157 
158 int RTNAME(AllocatableDeallocate)(Descriptor &descriptor, bool hasStat,
159     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
160   Terminator terminator{sourceFile, sourceLine};
161   if (!descriptor.IsAllocatable()) {
162     return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat);
163   }
164   if (!descriptor.IsAllocated()) {
165     return ReturnError(terminator, StatBaseNull, errMsg, hasStat);
166   }
167   return ReturnError(terminator, descriptor.Destroy(true), errMsg, hasStat);
168 }
169 
170 int RTNAME(AllocatableDeallocatePolymorphic)(Descriptor &descriptor,
171     const typeInfo::DerivedType *derivedType, bool hasStat,
172     const Descriptor *errMsg, const char *sourceFile, int sourceLine) {
173   int stat{RTNAME(AllocatableDeallocate)(
174       descriptor, hasStat, errMsg, sourceFile, sourceLine)};
175   if (stat == StatOk) {
176     DescriptorAddendum *addendum{descriptor.Addendum()};
177     if (addendum) {
178       addendum->set_derivedType(derivedType);
179     } else {
180       // Unlimited polymorphic descriptors initialized with
181       // AllocatableInitIntrinsic do not have an addendum. Make sure the
182       // derivedType is null in that case.
183       INTERNAL_CHECK(!derivedType);
184     }
185   }
186   return stat;
187 }
188 
189 void RTNAME(AllocatableDeallocateNoFinal)(
190     Descriptor &descriptor, const char *sourceFile, int sourceLine) {
191   Terminator terminator{sourceFile, sourceLine};
192   if (!descriptor.IsAllocatable()) {
193     ReturnError(terminator, StatInvalidDescriptor);
194   } else if (!descriptor.IsAllocated()) {
195     ReturnError(terminator, StatBaseNull);
196   } else {
197     ReturnError(terminator, descriptor.Destroy(false));
198   }
199 }
200 
201 // TODO: AllocatableCheckLengthParameter
202 }
203 } // namespace Fortran::runtime
204