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 int stat{RTNAME(AllocatableAllocate)( 172 alloc, hasStat, errMsg, sourceFile, sourceLine)}; 173 if (stat == StatOk) { 174 Terminator terminator{sourceFile, sourceLine}; 175 DoFromSourceAssign(alloc, source, terminator); 176 } 177 return stat; 178 } 179 180 int RTNAME(AllocatableDeallocate)(Descriptor &descriptor, bool hasStat, 181 const Descriptor *errMsg, const char *sourceFile, int sourceLine) { 182 Terminator terminator{sourceFile, sourceLine}; 183 if (!descriptor.IsAllocatable()) { 184 return ReturnError(terminator, StatInvalidDescriptor, errMsg, hasStat); 185 } 186 if (!descriptor.IsAllocated()) { 187 return ReturnError(terminator, StatBaseNull, errMsg, hasStat); 188 } 189 return ReturnError(terminator, 190 descriptor.Destroy( 191 /*finalize=*/true, /*destroyPointers=*/false, &terminator), 192 errMsg, hasStat); 193 } 194 195 int RTNAME(AllocatableDeallocatePolymorphic)(Descriptor &descriptor, 196 const typeInfo::DerivedType *derivedType, bool hasStat, 197 const Descriptor *errMsg, const char *sourceFile, int sourceLine) { 198 int stat{RTNAME(AllocatableDeallocate)( 199 descriptor, hasStat, errMsg, sourceFile, sourceLine)}; 200 if (stat == StatOk) { 201 DescriptorAddendum *addendum{descriptor.Addendum()}; 202 if (addendum) { 203 addendum->set_derivedType(derivedType); 204 } else { 205 // Unlimited polymorphic descriptors initialized with 206 // AllocatableInitIntrinsic do not have an addendum. Make sure the 207 // derivedType is null in that case. 208 INTERNAL_CHECK(!derivedType); 209 } 210 } 211 return stat; 212 } 213 214 void RTNAME(AllocatableDeallocateNoFinal)( 215 Descriptor &descriptor, const char *sourceFile, int sourceLine) { 216 Terminator terminator{sourceFile, sourceLine}; 217 if (!descriptor.IsAllocatable()) { 218 ReturnError(terminator, StatInvalidDescriptor); 219 } else if (!descriptor.IsAllocated()) { 220 ReturnError(terminator, StatBaseNull); 221 } else { 222 ReturnError(terminator, 223 descriptor.Destroy( 224 /*finalize=*/false, /*destroyPointers=*/false, &terminator)); 225 } 226 } 227 228 // TODO: AllocatableCheckLengthParameter 229 } 230 } // namespace Fortran::runtime 231