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