Bug Summary

File:build/source/flang/include/flang/Runtime/descriptor.h
Warning:line 219, column 17
2nd function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name array-constructor.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -isystem /build/source/llvm/../mlir/include -isystem tools/mlir/include -isystem tools/clang/include -isystem /build/source/llvm/../clang/include -D FLANG_INCLUDE_TESTS=1 -D FLANG_LITTLE_ENDIAN=1 -D FLANG_VENDOR="Debian " -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/flang/runtime -I /build/source/flang/runtime -I /build/source/flang/include -I tools/flang/include -I include -I /build/source/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U _GLIBCXX_ASSERTIONS -U _LIBCPP_ENABLE_ASSERTIONS -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -Wno-deprecated-copy -Wno-ctad-maybe-unsupported -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/flang/runtime/array-constructor.cpp

/build/source/flang/runtime/array-constructor.cpp

1//===-- runtime/array-constructor.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/array-constructor.h"
10#include "derived.h"
11#include "terminator.h"
12#include "type-info.h"
13#include "flang/Runtime/allocatable.h"
14#include "flang/Runtime/assign.h"
15#include "flang/Runtime/descriptor.h"
16
17namespace Fortran::runtime {
18
19// Initial allocation size for an array constructor temporary whose extent
20// cannot be pre-computed. This could be fined tuned if needed based on actual
21// program performance.
22// REAL(4), INTEGER(4), COMPLEX(2), ... -> 32 elements.
23// REAL(8), INTEGER(8), COMPLEX(4), ... -> 16 elements.
24// REAL(16), INTEGER(16), COMPLEX(8), ... -> 8 elements.
25// Bigger types -> 4 elements.
26static SubscriptValue initialAllocationSize(
27 SubscriptValue initialNumberOfElements, SubscriptValue elementBytes) {
28 // Try to guess an optimal initial allocation size in number of elements to
29 // avoid doing too many reallocation.
30 static constexpr SubscriptValue minNumberOfBytes{128};
31 static constexpr SubscriptValue minNumberOfElements{4};
32 SubscriptValue numberOfElements{initialNumberOfElements > minNumberOfElements
33 ? initialNumberOfElements
34 : minNumberOfElements};
35 SubscriptValue elementsForMinBytes{minNumberOfBytes / elementBytes};
36 return std::max(numberOfElements, elementsForMinBytes);
37}
38
39static void AllocateOrReallocateVectorIfNeeded(ArrayConstructorVector &vector,
40 Terminator &terminator, SubscriptValue previousToElements,
41 SubscriptValue fromElements) {
42 Descriptor &to{vector.to};
43 if (to.IsAllocatable() && !to.IsAllocated()) {
44 // The descriptor bounds may already be set here if the array constructor
45 // extent could be pre-computed, but information about length parameters
46 // was missing and required evaluating the first array constructor value.
47 if (previousToElements == 0) {
48 SubscriptValue allocationSize{
49 initialAllocationSize(fromElements, to.ElementBytes())};
50 to.GetDimension(0).SetBounds(1, allocationSize);
51 RTNAME(AllocatableAllocate)_FortranAAllocatableAllocate
52 (to, /*hasStat=*/false, /*errMsg=*/nullptr, vector.sourceFile,
53 vector.sourceLine);
54 to.GetDimension(0).SetBounds(1, fromElements);
55 vector.actualAllocationSize = allocationSize;
56 } else {
57 // Do not over-allocate if the final extent was known before pushing the
58 // first value: there should be no reallocation.
59 RUNTIME_CHECK(terminator, previousToElements >= fromElements)if (previousToElements >= fromElements) ; else (terminator
).CheckFailed("previousToElements >= fromElements", "flang/runtime/array-constructor.cpp"
, 59)
;
60 RTNAME(AllocatableAllocate)_FortranAAllocatableAllocate
61 (to, /*hasStat=*/false, /*errMsg=*/nullptr, vector.sourceFile,
62 vector.sourceLine);
63 vector.actualAllocationSize = previousToElements;
64 }
65 } else {
66 SubscriptValue newToElements{vector.nextValuePosition + fromElements};
67 if (to.IsAllocatable() && vector.actualAllocationSize < newToElements) {
68 // Reallocate. Ensure the current storage is at least doubled to avoid
69 // doing too many reallocations.
70 SubscriptValue requestedAllocationSize{
71 std::max(newToElements, vector.actualAllocationSize * 2)};
72 std::size_t newByteSize{requestedAllocationSize * to.ElementBytes()};
73 // realloc is undefined with zero new size and ElementBytes() may be null
74 // if the character length is null, or if "from" is a zero sized array.
75 if (newByteSize > 0) {
76 void *p{std::realloc(to.raw().base_addr, newByteSize)};
77 RUNTIME_CHECK(terminator, p)if (p) ; else (terminator).CheckFailed("p", "flang/runtime/array-constructor.cpp"
, 77)
;
78 to.set_base_addr(p);
79 }
80 vector.actualAllocationSize = requestedAllocationSize;
81 to.GetDimension(0).SetBounds(1, newToElements);
82 } else if (previousToElements < newToElements) {
83 // Storage is big enough, but descriptor extent must be increased because
84 // the final extent was not known before pushing array constructor values.
85 to.GetDimension(0).SetBounds(1, newToElements);
86 }
87 }
88}
89
90extern "C" {
91void RTNAME(InitArrayConstructorVector)_FortranAInitArrayConstructorVector(ArrayConstructorVector &vector,
92 Descriptor &to, bool useValueLengthParameters, int vectorClassSize,
93 const char *sourceFile, int sourceLine) {
94 Terminator terminator{vector.sourceFile, vector.sourceLine};
95 RUNTIME_CHECK(terminator,if (to.rank() == 1 && sizeof(ArrayConstructorVector) <=
static_cast<std::size_t>(vectorClassSize)) ; else (terminator
).CheckFailed("to.rank() == 1 && sizeof(ArrayConstructorVector) <= static_cast<std::size_t>(vectorClassSize)"
, "flang/runtime/array-constructor.cpp", 98)
96 to.rank() == 1 &&if (to.rank() == 1 && sizeof(ArrayConstructorVector) <=
static_cast<std::size_t>(vectorClassSize)) ; else (terminator
).CheckFailed("to.rank() == 1 && sizeof(ArrayConstructorVector) <= static_cast<std::size_t>(vectorClassSize)"
, "flang/runtime/array-constructor.cpp", 98)
97 sizeof(ArrayConstructorVector) <=if (to.rank() == 1 && sizeof(ArrayConstructorVector) <=
static_cast<std::size_t>(vectorClassSize)) ; else (terminator
).CheckFailed("to.rank() == 1 && sizeof(ArrayConstructorVector) <= static_cast<std::size_t>(vectorClassSize)"
, "flang/runtime/array-constructor.cpp", 98)
98 static_cast<std::size_t>(vectorClassSize))if (to.rank() == 1 && sizeof(ArrayConstructorVector) <=
static_cast<std::size_t>(vectorClassSize)) ; else (terminator
).CheckFailed("to.rank() == 1 && sizeof(ArrayConstructorVector) <= static_cast<std::size_t>(vectorClassSize)"
, "flang/runtime/array-constructor.cpp", 98)
;
99 SubscriptValue actualAllocationSize{
100 to.IsAllocated() ? static_cast<SubscriptValue>(to.Elements()) : 0};
101 (void)new (&vector) ArrayConstructorVector{to, /*nextValuePosition=*/0,
102 actualAllocationSize, sourceFile, sourceLine, useValueLengthParameters};
103}
104
105void RTNAME(PushArrayConstructorValue)_FortranAPushArrayConstructorValue(
106 ArrayConstructorVector &vector, const Descriptor &from) {
107 Terminator terminator{vector.sourceFile, vector.sourceLine};
108 Descriptor &to{vector.to};
109 SubscriptValue fromElements{static_cast<SubscriptValue>(from.Elements())};
110 SubscriptValue previousToElements{static_cast<SubscriptValue>(to.Elements())};
111 if (vector.useValueLengthParameters()) {
112 // Array constructor with no type spec.
113 if (to.IsAllocatable() && !to.IsAllocated()) {
114 // Takes length parameters, if any, from the first value.
115 // Note that "to" type must already be set by the caller of this API since
116 // it cannot be taken from "from" here: "from" may be polymorphic (have a
117 // dynamic type that differs from its declared type) and Fortran 2018 7.8
118 // point 4. says that the dynamic type of an array constructor is its
119 // declared type: it does not inherit the dynamic type of its ac-value
120 // even if if there is no type-spec.
121 if (to.type().IsCharacter()) {
122 to.raw().elem_len = from.ElementBytes();
123 } else if (auto *toAddendum{to.Addendum()}) {
124 if (const auto *fromAddendum{from.Addendum()}) {
125 if (const auto *toDerived{toAddendum->derivedType()}) {
126 std::size_t lenParms{toDerived->LenParameters()};
127 for (std::size_t j{0}; j < lenParms; ++j) {
128 toAddendum->SetLenParameterValue(
129 j, fromAddendum->LenParameterValue(j));
130 }
131 }
132 }
133 }
134 } else if (to.type().IsCharacter()) {
135 // Fortran 2018 7.8 point 2.
136 if (to.ElementBytes() != from.ElementBytes()) {
137 terminator.Crash("Array constructor: mismatched character lengths (%d "
138 "!= %d) between "
139 "values of an array constructor without type-spec",
140 to.ElementBytes() / to.type().GetCategoryAndKind()->second,
141 from.ElementBytes() / from.type().GetCategoryAndKind()->second);
142 }
143 }
144 }
145 // Otherwise, the array constructor had a type-spec and the length
146 // parameters are already in the "to" descriptor.
147
148 AllocateOrReallocateVectorIfNeeded(
149 vector, terminator, previousToElements, fromElements);
150
151 // Create descriptor for "to" element or section being copied to.
152 SubscriptValue lower[1]{
153 to.GetDimension(0).LowerBound() + vector.nextValuePosition};
154 SubscriptValue upper[1]{lower[0] + fromElements - 1};
155 SubscriptValue stride[1]{from.rank() == 0 ? 0 : 1};
156 StaticDescriptor<maxRank, true, 1> staticDesc;
157 Descriptor &toCurrentElement{staticDesc.descriptor()};
158 toCurrentElement.EstablishPointerSection(to, lower, upper, stride);
159 // Note: toCurrentElement and from have the same number of elements
160 // and "toCurrentElement" is not an allocatable so AssignTemporary
161 // below works even if "from" rank is bigger than one (and differs
162 // from "toCurrentElement") and not time is wasted reshaping
163 // "toCurrentElement" to "from" shape.
164 RTNAME(AssignTemporary)_FortranAAssignTemporary
165 (toCurrentElement, from, vector.sourceFile, vector.sourceLine);
166 vector.nextValuePosition += fromElements;
167}
168
169void RTNAME(PushArrayConstructorSimpleScalar)_FortranAPushArrayConstructorSimpleScalar(
170 ArrayConstructorVector &vector, void *from) {
171 Terminator terminator{vector.sourceFile, vector.sourceLine};
172 Descriptor &to{vector.to};
173 AllocateOrReallocateVectorIfNeeded(vector, terminator, to.Elements(), 1);
174 SubscriptValue subscript[1]{
175 to.GetDimension(0).LowerBound() + vector.nextValuePosition};
176 std::memcpy(to.Element<char>(subscript), from, to.ElementBytes());
1
Calling 'Descriptor::Element'
177 ++vector.nextValuePosition;
178}
179} // extern "C"
180} // namespace Fortran::runtime

/build/source/flang/include/flang/Runtime/descriptor.h

1//===-- include/flang/Runtime/descriptor.h ----------------------*- C++ -*-===//
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#ifndef FORTRAN_RUNTIME_DESCRIPTOR_H_
10#define FORTRAN_RUNTIME_DESCRIPTOR_H_
11
12// Defines data structures used during execution of a Fortran program
13// to implement nontrivial dummy arguments, pointers, allocatables,
14// function results, and the special behaviors of instances of derived types.
15// This header file includes and extends the published language
16// interoperability header that is required by the Fortran 2018 standard
17// as a subset of definitions suitable for exposure to user C/C++ code.
18// User C code is welcome to depend on that ISO_Fortran_binding.h file,
19// but should never reference this internal header.
20
21#include "flang/ISO_Fortran_binding.h"
22#include "flang/Runtime/memory.h"
23#include "flang/Runtime/type-code.h"
24#include <algorithm>
25#include <cassert>
26#include <cinttypes>
27#include <cstddef>
28#include <cstdio>
29#include <cstring>
30
31namespace Fortran::runtime::typeInfo {
32using TypeParameterValue = std::int64_t;
33class DerivedType;
34} // namespace Fortran::runtime::typeInfo
35
36namespace Fortran::runtime {
37
38using SubscriptValue = ISO::CFI_index_t;
39
40static constexpr int maxRank{CFI_MAX_RANK15};
41
42// A C++ view of the sole interoperable standard descriptor (ISO::CFI_cdesc_t)
43// and its type and per-dimension information.
44
45class Dimension {
46public:
47 SubscriptValue LowerBound() const { return raw_.lower_bound; }
48 SubscriptValue Extent() const { return raw_.extent; }
49 SubscriptValue UpperBound() const { return LowerBound() + Extent() - 1; }
50 SubscriptValue ByteStride() const { return raw_.sm; }
51
52 Dimension &SetBounds(SubscriptValue lower, SubscriptValue upper) {
53 if (upper >= lower) {
54 raw_.lower_bound = lower;
55 raw_.extent = upper - lower + 1;
56 } else {
57 raw_.lower_bound = 1;
58 raw_.extent = 0;
59 }
60 return *this;
61 }
62 // Do not use this API to cause the LB of an empty dimension
63 // to be anything other than 1. Use SetBounds() instead if you can.
64 Dimension &SetLowerBound(SubscriptValue lower) {
65 raw_.lower_bound = lower;
66 return *this;
67 }
68 Dimension &SetUpperBound(SubscriptValue upper) {
69 auto lower{raw_.lower_bound};
70 raw_.extent = upper >= lower ? upper - lower + 1 : 0;
71 return *this;
72 }
73 Dimension &SetExtent(SubscriptValue extent) {
74 raw_.extent = extent;
75 return *this;
76 }
77 Dimension &SetByteStride(SubscriptValue bytes) {
78 raw_.sm = bytes;
79 return *this;
80 }
81
82private:
83 ISO::CFI_dim_t raw_;
84};
85
86// The storage for this object follows the last used dim[] entry in a
87// Descriptor (CFI_cdesc_t) generic descriptor. Space matters here, since
88// descriptors serve as POINTER and ALLOCATABLE components of derived type
89// instances. The presence of this structure is implied by the flag
90// CFI_cdesc_t.f18Addendum, and the number of elements in the len_[]
91// array is determined by derivedType_->LenParameters().
92class DescriptorAddendum {
93public:
94 explicit DescriptorAddendum(const typeInfo::DerivedType *dt = nullptr)
95 : derivedType_{dt} {}
96 DescriptorAddendum &operator=(const DescriptorAddendum &);
97
98 const typeInfo::DerivedType *derivedType() const { return derivedType_; }
99 DescriptorAddendum &set_derivedType(const typeInfo::DerivedType *dt) {
100 derivedType_ = dt;
101 return *this;
102 }
103
104 std::size_t LenParameters() const;
105
106 typeInfo::TypeParameterValue LenParameterValue(int which) const {
107 return len_[which];
108 }
109 static constexpr std::size_t SizeInBytes(int lenParameters) {
110 // TODO: Don't waste that last word if lenParameters == 0
111 return sizeof(DescriptorAddendum) +
112 std::max(lenParameters - 1, 0) * sizeof(typeInfo::TypeParameterValue);
113 }
114 std::size_t SizeInBytes() const;
115
116 void SetLenParameterValue(int which, typeInfo::TypeParameterValue x) {
117 len_[which] = x;
118 }
119
120 void Dump(FILE * = stdoutstdout) const;
121
122private:
123 const typeInfo::DerivedType *derivedType_;
124 typeInfo::TypeParameterValue len_[1]; // must be the last component
125 // The LEN type parameter values can also include captured values of
126 // specification expressions that were used for bounds and for LEN type
127 // parameters of components. The values have been truncated to the LEN
128 // type parameter's type, if shorter than 64 bits, then sign-extended.
129};
130
131// A C++ view of a standard descriptor object.
132class Descriptor {
133public:
134 // Be advised: this class type is not suitable for use when allocating
135 // a descriptor -- it is a dynamic view of the common descriptor format.
136 // If used in a simple declaration of a local variable or dynamic allocation,
137 // the size is going to be correct only by accident, since the true size of
138 // a descriptor depends on the number of its dimensions and the presence and
139 // size of an addendum, which depends on the type of the data.
140 // Use the class template StaticDescriptor (below) to declare a descriptor
141 // whose type and rank are fixed and known at compilation time. Use the
142 // Create() static member functions otherwise to dynamically allocate a
143 // descriptor.
144
145 Descriptor(const Descriptor &);
146 Descriptor &operator=(const Descriptor &);
147
148 // Returns the number of bytes occupied by an element of the given
149 // category and kind including any alignment padding required
150 // between adjacent elements.
151 static std::size_t BytesFor(TypeCategory category, int kind);
152
153 void Establish(TypeCode t, std::size_t elementBytes, void *p = nullptr,
154 int rank = maxRank, const SubscriptValue *extent = nullptr,
155 ISO::CFI_attribute_t attribute = CFI_attribute_other0,
156 bool addendum = false);
157 void Establish(TypeCategory, int kind, void *p = nullptr, int rank = maxRank,
158 const SubscriptValue *extent = nullptr,
159 ISO::CFI_attribute_t attribute = CFI_attribute_other0,
160 bool addendum = false);
161 void Establish(int characterKind, std::size_t characters, void *p = nullptr,
162 int rank = maxRank, const SubscriptValue *extent = nullptr,
163 ISO::CFI_attribute_t attribute = CFI_attribute_other0,
164 bool addendum = false);
165 void Establish(const typeInfo::DerivedType &dt, void *p = nullptr,
166 int rank = maxRank, const SubscriptValue *extent = nullptr,
167 ISO::CFI_attribute_t attribute = CFI_attribute_other0);
168
169 static OwningPtr<Descriptor> Create(TypeCode t, std::size_t elementBytes,
170 void *p = nullptr, int rank = maxRank,
171 const SubscriptValue *extent = nullptr,
172 ISO::CFI_attribute_t attribute = CFI_attribute_other0,
173 int derivedTypeLenParameters = 0);
174 static OwningPtr<Descriptor> Create(TypeCategory, int kind, void *p = nullptr,
175 int rank = maxRank, const SubscriptValue *extent = nullptr,
176 ISO::CFI_attribute_t attribute = CFI_attribute_other0);
177 static OwningPtr<Descriptor> Create(int characterKind,
178 SubscriptValue characters, void *p = nullptr, int rank = maxRank,
179 const SubscriptValue *extent = nullptr,
180 ISO::CFI_attribute_t attribute = CFI_attribute_other0);
181 static OwningPtr<Descriptor> Create(const typeInfo::DerivedType &dt,
182 void *p = nullptr, int rank = maxRank,
183 const SubscriptValue *extent = nullptr,
184 ISO::CFI_attribute_t attribute = CFI_attribute_other0);
185
186 ISO::CFI_cdesc_t &raw() { return raw_; }
187 const ISO::CFI_cdesc_t &raw() const { return raw_; }
188 std::size_t ElementBytes() const { return raw_.elem_len; }
189 int rank() const { return raw_.rank; }
190 TypeCode type() const { return TypeCode{raw_.type}; }
191
192 Descriptor &set_base_addr(void *p) {
193 raw_.base_addr = p;
194 return *this;
195 }
196
197 bool IsPointer() const { return raw_.attribute == CFI_attribute_pointer1; }
198 bool IsAllocatable() const {
199 return raw_.attribute == CFI_attribute_allocatable2;
200 }
201 bool IsAllocated() const { return raw_.base_addr != nullptr; }
202
203 Dimension &GetDimension(int dim) {
204 return *reinterpret_cast<Dimension *>(&raw_.dim[dim]);
205 }
206 const Dimension &GetDimension(int dim) const {
207 return *reinterpret_cast<const Dimension *>(&raw_.dim[dim]);
208 }
209
210 std::size_t SubscriptByteOffset(
211 int dim, SubscriptValue subscriptValue) const {
212 const Dimension &dimension{GetDimension(dim)};
213 return (subscriptValue - dimension.LowerBound()) * dimension.ByteStride();
214 }
215
216 std::size_t SubscriptsToByteOffset(const SubscriptValue subscript[]) const {
217 std::size_t offset{0};
218 for (int j{0}; j < raw_.rank; ++j) {
3
Assuming 'j' is < field 'rank'
4
Loop condition is true. Entering loop body
5
The value 1 is assigned to 'j'
6
Assuming 'j' is < field 'rank'
7
Loop condition is true. Entering loop body
219 offset += SubscriptByteOffset(j, subscript[j]);
8
2nd function call argument is an uninitialized value
220 }
221 return offset;
222 }
223
224 template <typename A = char> A *OffsetElement(std::size_t offset = 0) const {
225 return reinterpret_cast<A *>(
226 reinterpret_cast<char *>(raw_.base_addr) + offset);
227 }
228
229 template <typename A> A *Element(const SubscriptValue subscript[]) const {
230 return OffsetElement<A>(SubscriptsToByteOffset(subscript));
2
Calling 'Descriptor::SubscriptsToByteOffset'
231 }
232
233 template <typename A> A *ZeroBasedIndexedElement(std::size_t n) const {
234 SubscriptValue at[maxRank];
235 if (SubscriptsForZeroBasedElementNumber(at, n)) {
236 return Element<A>(at);
237 }
238 return nullptr;
239 }
240
241 int GetLowerBounds(SubscriptValue subscript[]) const {
242 for (int j{0}; j < raw_.rank; ++j) {
243 subscript[j] = GetDimension(j).LowerBound();
244 }
245 return raw_.rank;
246 }
247
248 int GetShape(SubscriptValue subscript[]) const {
249 for (int j{0}; j < raw_.rank; ++j) {
250 subscript[j] = GetDimension(j).Extent();
251 }
252 return raw_.rank;
253 }
254
255 // When the passed subscript vector contains the last (or first)
256 // subscripts of the array, these wrap the subscripts around to
257 // their first (or last) values and return false.
258 bool IncrementSubscripts(
259 SubscriptValue subscript[], const int *permutation = nullptr) const {
260 for (int j{0}; j < raw_.rank; ++j) {
261 int k{permutation ? permutation[j] : j};
262 const Dimension &dim{GetDimension(k)};
263 if (subscript[k]++ < dim.UpperBound()) {
264 return true;
265 }
266 subscript[k] = dim.LowerBound();
267 }
268 return false;
269 }
270
271 bool DecrementSubscripts(
272 SubscriptValue[], const int *permutation = nullptr) const;
273
274 // False when out of range.
275 bool SubscriptsForZeroBasedElementNumber(SubscriptValue subscript[],
276 std::size_t elementNumber, const int *permutation = nullptr) const {
277 if (raw_.rank == 0) {
278 return elementNumber == 0;
279 }
280 std::size_t dimCoefficient[maxRank];
281 int k0{permutation ? permutation[0] : 0};
282 dimCoefficient[0] = 1;
283 auto coefficient{static_cast<std::size_t>(GetDimension(k0).Extent())};
284 for (int j{1}; j < raw_.rank; ++j) {
285 int k{permutation ? permutation[j] : j};
286 const Dimension &dim{GetDimension(k)};
287 dimCoefficient[j] = coefficient;
288 coefficient *= dim.Extent();
289 }
290 if (elementNumber >= coefficient) {
291 return false; // out of range
292 }
293 for (int j{raw_.rank - 1}; j > 0; --j) {
294 int k{permutation ? permutation[j] : j};
295 const Dimension &dim{GetDimension(k)};
296 std::size_t quotient{elementNumber / dimCoefficient[j]};
297 subscript[k] = quotient + dim.LowerBound();
298 elementNumber -= quotient * dimCoefficient[j];
299 }
300 subscript[k0] = elementNumber + GetDimension(k0).LowerBound();
301 return true;
302 }
303
304 std::size_t ZeroBasedElementNumber(
305 const SubscriptValue *, const int *permutation = nullptr) const;
306
307 DescriptorAddendum *Addendum() {
308 if (raw_.f18Addendum != 0) {
309 return reinterpret_cast<DescriptorAddendum *>(&GetDimension(rank()));
310 } else {
311 return nullptr;
312 }
313 }
314 const DescriptorAddendum *Addendum() const {
315 if (raw_.f18Addendum != 0) {
316 return reinterpret_cast<const DescriptorAddendum *>(
317 &GetDimension(rank()));
318 } else {
319 return nullptr;
320 }
321 }
322
323 // Returns size in bytes of the descriptor (not the data)
324 static constexpr std::size_t SizeInBytes(
325 int rank, bool addendum = false, int lengthTypeParameters = 0) {
326 std::size_t bytes{sizeof(Descriptor) - sizeof(Dimension)};
327 bytes += rank * sizeof(Dimension);
328 if (addendum || lengthTypeParameters > 0) {
329 bytes += DescriptorAddendum::SizeInBytes(lengthTypeParameters);
330 }
331 return bytes;
332 }
333
334 std::size_t SizeInBytes() const;
335
336 std::size_t Elements() const;
337
338 // Allocate() assumes Elements() and ElementBytes() work;
339 // define the extents of the dimensions and the element length
340 // before calling. It (re)computes the byte strides after
341 // allocation. Does not allocate automatic components or
342 // perform default component initialization.
343 int Allocate();
344
345 // Deallocates storage; does not call FINAL subroutines or
346 // deallocate allocatable/automatic components.
347 int Deallocate();
348
349 // Deallocates storage, including allocatable and automatic
350 // components. Optionally invokes FINAL subroutines.
351 int Destroy(bool finalize = false, bool destroyPointers = false);
352
353 bool IsContiguous(int leadingDimensions = maxRank) const {
354 auto bytes{static_cast<SubscriptValue>(ElementBytes())};
355 if (leadingDimensions > raw_.rank) {
356 leadingDimensions = raw_.rank;
357 }
358 for (int j{0}; j < leadingDimensions; ++j) {
359 const Dimension &dim{GetDimension(j)};
360 if (bytes != dim.ByteStride()) {
361 return false;
362 }
363 bytes *= dim.Extent();
364 }
365 return true;
366 }
367
368 // Establishes a pointer to a section or element.
369 bool EstablishPointerSection(const Descriptor &source,
370 const SubscriptValue *lower = nullptr,
371 const SubscriptValue *upper = nullptr,
372 const SubscriptValue *stride = nullptr);
373
374 void Check() const;
375
376 void Dump(FILE * = stdoutstdout) const;
377
378private:
379 ISO::CFI_cdesc_t raw_;
380};
381static_assert(sizeof(Descriptor) == sizeof(ISO::CFI_cdesc_t));
382
383// Properly configured instances of StaticDescriptor will occupy the
384// exact amount of storage required for the descriptor, its dimensional
385// information, and possible addendum. To build such a static descriptor,
386// declare an instance of StaticDescriptor<>, extract a reference to its
387// descriptor via the descriptor() accessor, and then built a Descriptor
388// therein via descriptor.Establish(), e.g.:
389// StaticDescriptor<R,A,LP> statDesc;
390// Descriptor &descriptor{statDesc.descriptor()};
391// descriptor.Establish( ... );
392template <int MAX_RANK = maxRank, bool ADDENDUM = false, int MAX_LEN_PARMS = 0>
393class alignas(Descriptor) StaticDescriptor {
394public:
395 static constexpr int maxRank{MAX_RANK};
396 static constexpr int maxLengthTypeParameters{MAX_LEN_PARMS};
397 static constexpr bool hasAddendum{ADDENDUM || MAX_LEN_PARMS > 0};
398 static constexpr std::size_t byteSize{
399 Descriptor::SizeInBytes(maxRank, hasAddendum, maxLengthTypeParameters)};
400
401 Descriptor &descriptor() { return *reinterpret_cast<Descriptor *>(storage_); }
402 const Descriptor &descriptor() const {
403 return *reinterpret_cast<const Descriptor *>(storage_);
404 }
405
406 void Check() {
407 assert(descriptor().rank() <= maxRank)(static_cast <bool> (descriptor().rank() <= maxRank)
? void (0) : __assert_fail ("descriptor().rank() <= maxRank"
, "flang/include/flang/Runtime/descriptor.h", 407, __extension__
__PRETTY_FUNCTION__))
;
408 assert(descriptor().SizeInBytes() <= byteSize)(static_cast <bool> (descriptor().SizeInBytes() <= byteSize
) ? void (0) : __assert_fail ("descriptor().SizeInBytes() <= byteSize"
, "flang/include/flang/Runtime/descriptor.h", 408, __extension__
__PRETTY_FUNCTION__))
;
409 if (DescriptorAddendum * addendum{descriptor().Addendum()}) {
410 assert(hasAddendum)(static_cast <bool> (hasAddendum) ? void (0) : __assert_fail
("hasAddendum", "flang/include/flang/Runtime/descriptor.h", 410
, __extension__ __PRETTY_FUNCTION__))
;
411 assert(addendum->LenParameters() <= maxLengthTypeParameters)(static_cast <bool> (addendum->LenParameters() <=
maxLengthTypeParameters) ? void (0) : __assert_fail ("addendum->LenParameters() <= maxLengthTypeParameters"
, "flang/include/flang/Runtime/descriptor.h", 411, __extension__
__PRETTY_FUNCTION__))
;
412 } else {
413 assert(!hasAddendum)(static_cast <bool> (!hasAddendum) ? void (0) : __assert_fail
("!hasAddendum", "flang/include/flang/Runtime/descriptor.h",
413, __extension__ __PRETTY_FUNCTION__))
;
414 assert(maxLengthTypeParameters == 0)(static_cast <bool> (maxLengthTypeParameters == 0) ? void
(0) : __assert_fail ("maxLengthTypeParameters == 0", "flang/include/flang/Runtime/descriptor.h"
, 414, __extension__ __PRETTY_FUNCTION__))
;
415 }
416 descriptor().Check();
417 }
418
419private:
420 char storage_[byteSize]{};
421};
422} // namespace Fortran::runtime
423#endif // FORTRAN_RUNTIME_DESCRIPTOR_H_